mirror of https://github.com/veypi/OneAuth.git
add user role auth page
parent
bc3f5e0b0c
commit
bcbfc0380a
@ -0,0 +1,12 @@
|
|||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/veypi/OneBD"
|
||||||
|
"github.com/veypi/OneBD/rfc"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Router(r OneBD.Router) {
|
||||||
|
r.Set("/", appHandlerP, rfc.MethodPost, rfc.MethodGet)
|
||||||
|
r.Set("/:uuid", appHandlerP, rfc.MethodGet, rfc.MethodPatch)
|
||||||
|
r.Set("/:uuid/user/:id", auHandlerP, rfc.MethodAll)
|
||||||
|
}
|
@ -0,0 +1,108 @@
|
|||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"OneAuth/cfg"
|
||||||
|
"OneAuth/libs/app"
|
||||||
|
"OneAuth/libs/auth"
|
||||||
|
"OneAuth/libs/base"
|
||||||
|
"OneAuth/libs/oerr"
|
||||||
|
"OneAuth/models"
|
||||||
|
"github.com/veypi/OneBD"
|
||||||
|
)
|
||||||
|
|
||||||
|
var auHandlerP = OneBD.NewHandlerPool(func() OneBD.Handler {
|
||||||
|
h := &appUserHandler{}
|
||||||
|
return h
|
||||||
|
})
|
||||||
|
|
||||||
|
type appUserHandler struct {
|
||||||
|
base.ApiHandler
|
||||||
|
uuid string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *appUserHandler) Init(m OneBD.Meta) error {
|
||||||
|
h.uuid = m.Params("uuid")
|
||||||
|
if h.uuid == "-" {
|
||||||
|
h.uuid = ""
|
||||||
|
}
|
||||||
|
return h.ApiHandler.Init(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *appUserHandler) Get() (interface{}, error) {
|
||||||
|
id := h.Meta().ParamsInt("id")
|
||||||
|
if h.uuid == "" && id == 0 {
|
||||||
|
return nil, oerr.ApiArgsMissing
|
||||||
|
}
|
||||||
|
if uint(id) != h.Payload.ID && !h.Payload.GetAuth(auth.User, h.uuid).CanRead() {
|
||||||
|
return nil, oerr.NoAuth
|
||||||
|
}
|
||||||
|
au := &models.AppUser{
|
||||||
|
UserID: uint(id),
|
||||||
|
AppUUID: h.uuid,
|
||||||
|
}
|
||||||
|
list := make([]*models.AppUser, 0, 10)
|
||||||
|
err := cfg.DB().Preload("User").Where(au).Find(&list).Error
|
||||||
|
return list, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *appUserHandler) Post() (interface{}, error) {
|
||||||
|
id := h.Meta().ParamsInt("id")
|
||||||
|
if h.uuid == "" || id <= 0 {
|
||||||
|
return nil, oerr.ApiArgsMissing
|
||||||
|
}
|
||||||
|
status := models.AUOK
|
||||||
|
target := &models.App{}
|
||||||
|
err := cfg.DB().Where("uuid = ?", h.uuid).First(target).Error
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if target.EnableRegister {
|
||||||
|
status = models.AUApply
|
||||||
|
}
|
||||||
|
au, err := app.AddUser(cfg.DB(), h.uuid, uint(id), target.InitRoleID, status)
|
||||||
|
return au, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *appUserHandler) Update() (interface{}, error) {
|
||||||
|
id := h.Meta().ParamsInt("id")
|
||||||
|
if h.uuid == "" || id <= 0 {
|
||||||
|
return nil, oerr.ApiArgsMissing
|
||||||
|
}
|
||||||
|
props := struct {
|
||||||
|
Status string `json:"status"`
|
||||||
|
}{}
|
||||||
|
err := h.Meta().ReadJson(&props)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if uint(id) != h.Payload.ID && !h.Payload.GetAuth(auth.User, h.uuid).CanUpdate() {
|
||||||
|
return nil, oerr.NoAuth
|
||||||
|
}
|
||||||
|
au := &models.AppUser{
|
||||||
|
UserID: uint(id),
|
||||||
|
AppUUID: h.uuid,
|
||||||
|
}
|
||||||
|
err = cfg.DB().Where(au).Update("status", props.Status).Error
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *appUserHandler) Delete() (interface{}, error) {
|
||||||
|
id := h.Meta().ParamsInt("id")
|
||||||
|
if h.uuid == "" && id <= 0 {
|
||||||
|
return nil, oerr.ApiArgsMissing
|
||||||
|
}
|
||||||
|
if uint(id) != h.Payload.ID && h.Payload.GetAuth(auth.User, h.uuid).CanDelete() {
|
||||||
|
return nil, oerr.NoAuth
|
||||||
|
}
|
||||||
|
au := &models.AppUser{
|
||||||
|
AppUUID: h.uuid,
|
||||||
|
UserID: uint(id),
|
||||||
|
}
|
||||||
|
list := make([]*models.AppUser, 0, 10)
|
||||||
|
err := cfg.DB().Where(au).Delete(&list).Error
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = cfg.DB().Delete(&list).Error
|
||||||
|
return nil, err
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
import {Interface} from './interface'
|
||||||
|
import ajax from './ajax'
|
||||||
|
import {BaseUrl} from './setting'
|
||||||
|
|
||||||
|
export default (uuid: string) => {
|
||||||
|
return {
|
||||||
|
local: BaseUrl + 'app/' + uuid + '/auth/',
|
||||||
|
get(id: number) {
|
||||||
|
return new Interface(ajax.get, this.local + id)
|
||||||
|
},
|
||||||
|
list(appUUID: string, user_id: number) {
|
||||||
|
return new Interface(ajax.get, this.local, {uuid: appUUID, id: user_id})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,59 @@
|
|||||||
|
import {store} from "@/store";
|
||||||
|
|
||||||
|
export type SuccessFunction<T> = (e: any) => void;
|
||||||
|
export type FailedFunction<T> = (e: any) => void;
|
||||||
|
|
||||||
|
const Code = {
|
||||||
|
42011: '无操作权限',
|
||||||
|
22031: '资源不存在 或 您无权操作该资源'
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Interface {
|
||||||
|
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) {
|
||||||
|
if (data.code === 40001) {
|
||||||
|
// no login
|
||||||
|
store.commit('user/logout')
|
||||||
|
return
|
||||||
|
// @ts-ignore
|
||||||
|
} else if (data.code === 42011 && window.$msg) {
|
||||||
|
// @ts-ignore
|
||||||
|
window.$msg.warning('无权限')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
|
||||||
|
// @ts-ignore
|
||||||
|
if (data && data.code && Code[data.code]) {
|
||||||
|
}
|
||||||
|
if (fail) {
|
||||||
|
fail(data.err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const newSuccess = function (data: any) {
|
||||||
|
if (Number(data.status) === 1) {
|
||||||
|
if (success) {
|
||||||
|
success(data.content)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newFail(data)
|
||||||
|
if (data.code === 41001) {
|
||||||
|
store.commit('user/logout')
|
||||||
|
// bus.$emit('log_out')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.method(this.api, this.data, newSuccess, newFail)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
import {BaseUrl} from './setting'
|
||||||
|
import {Interface} from './interface'
|
||||||
|
import ajax from './ajax'
|
||||||
|
|
||||||
|
export default (uuid: string) => {
|
||||||
|
return {
|
||||||
|
local: BaseUrl +'app/' + uuid + '/role/',
|
||||||
|
get(id: number) {
|
||||||
|
return new Interface(ajax.get, this.local + id)
|
||||||
|
},
|
||||||
|
list() {
|
||||||
|
return new Interface(ajax.get, this.local)
|
||||||
|
},
|
||||||
|
create(uuid: string, name: string) {
|
||||||
|
return new Interface(ajax.post, this.local, {
|
||||||
|
uuid: uuid,
|
||||||
|
name: name,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
bind(id: number, aid: number) {
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
import {Base64} from "js-base64";
|
||||||
|
import {Interface} from './interface'
|
||||||
|
import ajax from './ajax'
|
||||||
|
import {BaseUrl} from './setting'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
local: BaseUrl + 'user/',
|
||||||
|
register(username: string, password: string, prop?: any) {
|
||||||
|
const data = Object.assign({
|
||||||
|
username: username,
|
||||||
|
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)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,77 @@
|
|||||||
|
export const R = {
|
||||||
|
// 应用管理配置权限
|
||||||
|
App: 'app',
|
||||||
|
// 用户管理和绑定应用权限
|
||||||
|
User: 'user',
|
||||||
|
// 权限资源定义权限
|
||||||
|
Resource: 'resource',
|
||||||
|
// 角色管理和绑定用户权限
|
||||||
|
Role: 'role',
|
||||||
|
// 权限管理和绑定角色权限
|
||||||
|
Auth: 'auth',
|
||||||
|
}
|
||||||
|
|
||||||
|
const level = {
|
||||||
|
None: 0,
|
||||||
|
Do: 1,
|
||||||
|
Part: 1,
|
||||||
|
Read: 2,
|
||||||
|
Create: 3,
|
||||||
|
Update: 4,
|
||||||
|
Delete: 5,
|
||||||
|
All: 6
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Auth {
|
||||||
|
rid: string
|
||||||
|
ruid: string
|
||||||
|
level: number
|
||||||
|
}
|
||||||
|
|
||||||
|
class authLevel {
|
||||||
|
level = level.None
|
||||||
|
constructor(level: number) {
|
||||||
|
this.level = level
|
||||||
|
}
|
||||||
|
CanDo(): boolean {
|
||||||
|
return this.level >= level.Do
|
||||||
|
}
|
||||||
|
CanRead(): boolean {
|
||||||
|
return this.level >= level.Read
|
||||||
|
}
|
||||||
|
CanCreate(): boolean {
|
||||||
|
return this.level >= level.Create
|
||||||
|
}
|
||||||
|
CanUpdate(): boolean {
|
||||||
|
return this.level >= level.Update
|
||||||
|
}
|
||||||
|
CanDelete(): boolean {
|
||||||
|
return this.level >= level.Delete
|
||||||
|
}
|
||||||
|
CanDoAny(): boolean {
|
||||||
|
return this.level >= level.All
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Auths {
|
||||||
|
private readonly list: [Auth]
|
||||||
|
|
||||||
|
constructor(auths: [Auth]) {
|
||||||
|
this.list = auths
|
||||||
|
}
|
||||||
|
|
||||||
|
Get(rid: string, ruid: string): authLevel {
|
||||||
|
let l = level.None
|
||||||
|
for (let i of this.list) {
|
||||||
|
if (i.rid == rid && (i.ruid === '' || i.ruid === ruid) && i.level > l) {
|
||||||
|
l = i.level
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new authLevel(l)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function NewAuths(a: any) {
|
||||||
|
return new Auths(a)
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
<template>
|
||||||
|
<n-layout has-sider>
|
||||||
|
<n-layout-sider
|
||||||
|
collapse-mode="transform"
|
||||||
|
:collapsed-width="0"
|
||||||
|
:width="150"
|
||||||
|
show-trigger="bar"
|
||||||
|
content-style="padding: 4px;"
|
||||||
|
bordered
|
||||||
|
default-collapsed
|
||||||
|
:native-scrollbar="false"
|
||||||
|
style="height: calc(100vh - 108px)"
|
||||||
|
>
|
||||||
|
<slot name="sider"></slot>
|
||||||
|
</n-layout-sider>
|
||||||
|
<n-layout style="height: calc(100vh - 108px);padding-left: 20px" :native-scrollbar="false">
|
||||||
|
<slot></slot>
|
||||||
|
<n-back-top>
|
||||||
|
</n-back-top>
|
||||||
|
</n-layout>
|
||||||
|
</n-layout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,27 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<h1 class="page-h1">首页</h1>
|
||||||
|
{{ uuid }}
|
||||||
|
{{ app }}
|
||||||
|
<div :ref="el => nav[6]=el" class="my-80">123123</div>
|
||||||
|
<div :ref="el => nav[k-1]=el" class="mb-64 text-center" v-for="(k) in [1,2,3,4,5,6]" :key="k">
|
||||||
|
{{ k }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import {inject, ref} from "vue";
|
||||||
|
|
||||||
|
let uuid = inject('uuid')
|
||||||
|
let app = inject('app')
|
||||||
|
let nav = ref([])
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
nav
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,73 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<h1 class="page-h1">角色管理</h1>
|
||||||
|
<n-data-table
|
||||||
|
:bordered="false"
|
||||||
|
:columns="columns"
|
||||||
|
:data="roles"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import {h, inject, onMounted, Ref, ref} from 'vue'
|
||||||
|
import api from '@/api'
|
||||||
|
import {NButton} from 'naive-ui'
|
||||||
|
|
||||||
|
let roles = ref([])
|
||||||
|
let uuid = inject<Ref>('uuid')
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: 'ID',
|
||||||
|
key: 'id',
|
||||||
|
width: 50,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '角色名',
|
||||||
|
key: 'name',
|
||||||
|
width: 100,
|
||||||
|
fixed: 'left',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
key: 'created_at',
|
||||||
|
fixed: 'left',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '绑定用户数',
|
||||||
|
key: 'user_count',
|
||||||
|
fixed: 'left',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
key: '',
|
||||||
|
render(row) {
|
||||||
|
return [
|
||||||
|
h(NButton, {
|
||||||
|
class: 'mr-1',
|
||||||
|
size: 'small',
|
||||||
|
onClick: () => console.log(row),
|
||||||
|
},
|
||||||
|
{default: () => '查看权限'}),
|
||||||
|
h(NButton, {
|
||||||
|
class: 'mr-1',
|
||||||
|
size: 'small',
|
||||||
|
onClick: () => console.log(row),
|
||||||
|
},
|
||||||
|
{default: () => '查看用户'},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
onMounted(() => {
|
||||||
|
api.role(uuid.value).list().Start(e => {
|
||||||
|
roles.value = e
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,74 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<div style="line-height: 48px" class="inline-block mt-16 grid grid-cols-5 w-1/3 text-center gap-4">
|
||||||
|
<div>应用名</div>
|
||||||
|
<div class="col-span-4">
|
||||||
|
<n-input v-model:value="data.name" @blur="update('name')"></n-input>
|
||||||
|
</div>
|
||||||
|
<div>logo</div>
|
||||||
|
<div class="col-span-4">
|
||||||
|
<n-upload
|
||||||
|
action="/api/upload"
|
||||||
|
@finish="handleFinish"
|
||||||
|
:show-file-list="false"
|
||||||
|
>
|
||||||
|
<n-avatar size="large" round :src="data.icon">
|
||||||
|
</n-avatar>
|
||||||
|
</n-upload>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import {inject, watch, ref, onMounted} from "vue";
|
||||||
|
import api from "@/api";
|
||||||
|
import {useMessage} from "naive-ui";
|
||||||
|
|
||||||
|
let msg = useMessage()
|
||||||
|
let app: any = inject('app')
|
||||||
|
let data = ref({
|
||||||
|
name: '',
|
||||||
|
icon: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
function handleFinish(e: any) {
|
||||||
|
if (e.event.target.response) {
|
||||||
|
let d = JSON.parse(e.event.target.response)
|
||||||
|
if (d.status === 1) {
|
||||||
|
data.value.icon = d.content
|
||||||
|
update('icon')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
msg.error('上传失败')
|
||||||
|
data.value.icon = app.value.icon
|
||||||
|
}
|
||||||
|
|
||||||
|
function update(key: string) {
|
||||||
|
// @ts-ignore
|
||||||
|
let v = data.value[key]
|
||||||
|
if (v === app.value[key]) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
api.app.update(app.value.uuid, {[key]: v}).Start(e => {
|
||||||
|
msg.success('更新成功')
|
||||||
|
app.value[key] = v
|
||||||
|
}, e => {
|
||||||
|
data.value[key] = app.value[key]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function sync() {
|
||||||
|
data.value.name = app.value.name
|
||||||
|
data.value.icon = app.value.icon
|
||||||
|
}
|
||||||
|
watch(app, sync)
|
||||||
|
onMounted(sync)
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,78 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<h1 class="page-h1">用户名单</h1>
|
||||||
|
<n-data-table
|
||||||
|
:bordered="false"
|
||||||
|
:columns="columns"
|
||||||
|
:data="users"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import {inject, onMounted, ref, h} from "vue";
|
||||||
|
import api from "@/api";
|
||||||
|
import {NTag} from 'naive-ui'
|
||||||
|
|
||||||
|
let uuid: any = inject('uuid')
|
||||||
|
let users = ref([])
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
api.app.user(uuid.value as string).list(0).Start(e => {
|
||||||
|
users.value = e
|
||||||
|
console.log(e)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: 'ID',
|
||||||
|
key: 'user_id',
|
||||||
|
width: 50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '用户',
|
||||||
|
key: 'user.username',
|
||||||
|
width: 200,
|
||||||
|
fixed: 'left'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '加入时间',
|
||||||
|
key: 'user.created_at',
|
||||||
|
fixed: 'left'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Status',
|
||||||
|
key: 'status',
|
||||||
|
render(row) {
|
||||||
|
let t = statusTag(row.status)
|
||||||
|
return h(NTag,{
|
||||||
|
'type': t[1]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
default: () => t[0]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
function statusTag(s: string) {
|
||||||
|
switch (s) {
|
||||||
|
case 'ok':
|
||||||
|
return ['正常', 'success']
|
||||||
|
case "apply":
|
||||||
|
return ['申请中', 'info']
|
||||||
|
case 'deny':
|
||||||
|
return ['拒绝', '']
|
||||||
|
case 'disabled':
|
||||||
|
return ['禁用', 'warning']
|
||||||
|
}
|
||||||
|
return ['未知', '']
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -1,10 +1,95 @@
|
|||||||
<template>
|
<template>
|
||||||
<div></div>
|
<div class="flex items-center justify-center">
|
||||||
|
<div
|
||||||
|
:style="{background:Theme.me.lightBox, 'box-shadow': Theme.me.lightBoxShadow}"
|
||||||
|
class="px-10 pb-9 pt-28 rounded-xl w-96">
|
||||||
|
<n-form label-width="70px" label-align="left" :model="data" ref="form_ref" label-placement="left" :rules="rules">
|
||||||
|
<n-form-item required label="用户名" path="username">
|
||||||
|
<n-input @keydown.enter="divs[1].focus()" :ref="el => {if (el)divs[0]=el}"
|
||||||
|
v-model:value="data.username"></n-input>
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item required label="密码" path="password">
|
||||||
|
<n-input @keydown.enter="divs[2].focus()" :ref="el => {if (el) divs[1]=el}" v-model:value="data.password"
|
||||||
|
type="password"></n-input>
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item required label="重复密码" path="pass">
|
||||||
|
<n-input @keydown.enter="register" :ref="el => {if (el) divs[2]=el}" v-model:value="data.pass"
|
||||||
|
type="password"></n-input>
|
||||||
|
</n-form-item>
|
||||||
|
<div class="flex justify-around mt-4">
|
||||||
|
<n-button @click="register">注册</n-button>
|
||||||
|
</div>
|
||||||
|
</n-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import {onMounted, ref} from "vue";
|
||||||
|
import {Theme} from "@/theme";
|
||||||
|
import {useMessage} from 'naive-ui'
|
||||||
|
import api from "@/api"
|
||||||
|
import {useRouter} from "vue-router";
|
||||||
|
|
||||||
|
let msg = useMessage()
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const divs = ref([])
|
||||||
|
let form_ref = ref(null)
|
||||||
|
let data = ref({
|
||||||
|
username: '',
|
||||||
|
password: '',
|
||||||
|
pass: ''
|
||||||
|
})
|
||||||
|
let rules = {
|
||||||
|
username: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
validator(r: any, v: any) {
|
||||||
|
return (v && v.length >= 3 && v.length <= 16) || new Error('长度要求3~16')
|
||||||
|
},
|
||||||
|
trigger: ['input', 'blur']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
password: [{
|
||||||
|
required: true,
|
||||||
|
validator(r: any, v: any) {
|
||||||
|
return (v && v.length >= 6 && v.length <= 16) || new Error('长度要求6~16')
|
||||||
|
},
|
||||||
|
trigger: ['input', 'blur']
|
||||||
|
}],
|
||||||
|
pass: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
validator(r: any, v: any) {
|
||||||
|
return (v && v === data.value.password) || new Error('密码不正确')
|
||||||
|
},
|
||||||
|
trigger: ['input', 'blur']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
function register() {
|
||||||
|
// @ts-ignore
|
||||||
|
form_ref.value.validate((e: any) => {
|
||||||
|
if (!e) {
|
||||||
|
api.user.register(data.value.username, data.value.password).Start((url: string) => {
|
||||||
|
msg.success('注册成功')
|
||||||
|
router.push({name: 'login'})
|
||||||
|
}, e => {
|
||||||
|
console.log(e)
|
||||||
|
msg.warning('注册失败:' + e)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (divs.value[0]) {
|
||||||
|
// @ts-ignore
|
||||||
|
divs.value[0].focus()
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
> 1%
|
||||||
|
last 2 versions
|
||||||
|
not dead
|
@ -0,0 +1,5 @@
|
|||||||
|
[*.{js,jsx,ts,tsx,vue}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
@ -0,0 +1 @@
|
|||||||
|
src/libs/wwLogin.js
|
@ -0,0 +1,23 @@
|
|||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
env: {
|
||||||
|
node: true
|
||||||
|
},
|
||||||
|
extends: [
|
||||||
|
'plugin:vue/essential',
|
||||||
|
'@vue/standard',
|
||||||
|
'@vue/typescript/recommended'
|
||||||
|
],
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 2020
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
'object-curly-spacing': 0,
|
||||||
|
'space-before-function-paren': 0,
|
||||||
|
'@typescript-eslint/camelcase': 0,
|
||||||
|
'@typescript-eslint/no-empty-function': 0,
|
||||||
|
'@typescript-eslint/no-explicit-any': 0,
|
||||||
|
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
||||||
|
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
.DS_Store
|
||||||
|
node_modules
|
||||||
|
/dist
|
||||||
|
|
||||||
|
|
||||||
|
# local env files
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
|
||||||
|
# Log files
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
@ -0,0 +1,24 @@
|
|||||||
|
# oaf
|
||||||
|
|
||||||
|
## Project setup
|
||||||
|
```
|
||||||
|
yarn install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compiles and hot-reloads for development
|
||||||
|
```
|
||||||
|
yarn serve
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compiles and minifies for production
|
||||||
|
```
|
||||||
|
yarn build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lints and fixes files
|
||||||
|
```
|
||||||
|
yarn lint
|
||||||
|
```
|
||||||
|
|
||||||
|
### Customize configuration
|
||||||
|
See [Configuration Reference](https://cli.vuejs.org/config/).
|
@ -0,0 +1,5 @@
|
|||||||
|
module.exports = {
|
||||||
|
presets: [
|
||||||
|
'@vue/cli-plugin-babel/preset'
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"name": "oaf",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"serve": "vue-cli-service serve",
|
||||||
|
"build": "vue-cli-service build",
|
||||||
|
"lint": "vue-cli-service lint"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@veypi/one-icon": "^1.0.1",
|
||||||
|
"axios": "^0.21.1",
|
||||||
|
"core-js": "^3.6.5",
|
||||||
|
"js-base64": "^3.6.0",
|
||||||
|
"vue": "^2.6.11",
|
||||||
|
"vue-class-component": "^7.2.3",
|
||||||
|
"vue-m-message": "^3.1.0",
|
||||||
|
"vue-property-decorator": "^9.1.2",
|
||||||
|
"vue-router": "^3.2.0",
|
||||||
|
"vuetify": "^2.4.0",
|
||||||
|
"vuex": "^3.4.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@typescript-eslint/eslint-plugin": "^2.33.0",
|
||||||
|
"@typescript-eslint/parser": "^2.33.0",
|
||||||
|
"@vue/cli-plugin-babel": "~4.5.0",
|
||||||
|
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||||
|
"@vue/cli-plugin-router": "~4.5.0",
|
||||||
|
"@vue/cli-plugin-typescript": "~4.5.0",
|
||||||
|
"@vue/cli-plugin-vuex": "~4.5.0",
|
||||||
|
"@vue/cli-service": "~4.5.0",
|
||||||
|
"@vue/eslint-config-standard": "^5.1.2",
|
||||||
|
"@vue/eslint-config-typescript": "^5.0.2",
|
||||||
|
"eslint": "^6.7.2",
|
||||||
|
"eslint-plugin-import": "^2.20.2",
|
||||||
|
"eslint-plugin-node": "^11.1.0",
|
||||||
|
"eslint-plugin-promise": "^4.2.1",
|
||||||
|
"eslint-plugin-standard": "^4.0.0",
|
||||||
|
"eslint-plugin-vue": "^6.2.2",
|
||||||
|
"less": "^3.0.4",
|
||||||
|
"less-loader": "^5.0.0",
|
||||||
|
"sass": "^1.32.0",
|
||||||
|
"sass-loader": "^10.0.0",
|
||||||
|
"typescript": "~3.9.3",
|
||||||
|
"vue-cli-plugin-vuetify": "^2.2.2",
|
||||||
|
"vue-template-compiler": "^2.6.11",
|
||||||
|
"vuetify-loader": "^1.7.0"
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
File diff suppressed because one or more lines are too long
@ -0,0 +1,20 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
|
<!-- <link rel="icon" href="<%= BASE_URL %>favicon.ico">-->
|
||||||
|
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||||
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900">
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@mdi/font@latest/css/materialdesignicons.min.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<noscript>
|
||||||
|
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
|
||||||
|
Please enable it to continue.</strong>
|
||||||
|
</noscript>
|
||||||
|
<div id="app"></div>
|
||||||
|
<!-- built files will be auto injected -->
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,63 @@
|
|||||||
|
<template>
|
||||||
|
<v-app @mousewheel.native.prevent="">
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<v-main>
|
||||||
|
<router-view></router-view>
|
||||||
|
</v-main>
|
||||||
|
</v-app>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<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')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
@import './assets/common';
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
.full_size;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app {
|
||||||
|
.full_size;
|
||||||
|
//.none_select;
|
||||||
|
font-family: 'Avenir', Helvetica, Arial, sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
color: #2c3e50;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
display: none; /* Chrome Safari */
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,65 @@
|
|||||||
|
import axios from 'axios'
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ajax
|
@ -0,0 +1,216 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 light <light@light-laptop>
|
||||||
|
*
|
||||||
|
* Distributed under terms of the MIT license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Vue from 'vue'
|
||||||
|
import {Base64} from 'js-base64'
|
||||||
|
import ajax from './ajax'
|
||||||
|
import store from '@/store'
|
||||||
|
|
||||||
|
export type SuccessFunction<T> = (e: any) => void;
|
||||||
|
export type FailedFunction<T> = (e: any) => void;
|
||||||
|
|
||||||
|
const Code = {
|
||||||
|
42011: '无操作权限',
|
||||||
|
22031: '资源不存在 或 您无权操作该资源'
|
||||||
|
}
|
||||||
|
|
||||||
|
class Interface {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
const Api = {
|
||||||
|
install(vue: typeof Vue): void {
|
||||||
|
vue.prototype.$api = api
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export {Api}
|
||||||
|
export default api
|
@ -0,0 +1,25 @@
|
|||||||
|
pre {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.full_size {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.none_select {
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.none_border{
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
.none_border_input {
|
||||||
|
.ivu-input {
|
||||||
|
.none_border;
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 6.7 KiB |
@ -0,0 +1 @@
|
|||||||
|
<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>
|
After Width: | Height: | Size: 539 B |
@ -0,0 +1,44 @@
|
|||||||
|
<template>
|
||||||
|
<div id="wx_reg"></div>
|
||||||
|
</template>
|
||||||
|
<script lang='ts'>
|
||||||
|
import {Component, Vue, Prop} from 'vue-property-decorator'
|
||||||
|
import '@/libs/wwLogin.js'
|
||||||
|
|
||||||
|
@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() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,33 @@
|
|||||||
|
<template>
|
||||||
|
<v-card class="core" elevation="4">
|
||||||
|
<v-system-bar color="info">
|
||||||
|
<one-icon>mail</one-icon>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<one-icon>user-group</one-icon>
|
||||||
|
<span>*{{ core.user_count }}</span>
|
||||||
|
</v-system-bar>
|
||||||
|
<div></div>
|
||||||
|
</v-card>
|
||||||
|
</template>
|
||||||
|
<script lang='ts'>
|
||||||
|
import {Component, Prop, Vue} from 'vue-property-decorator'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
components: {}
|
||||||
|
})
|
||||||
|
export default class AppCard extends Vue {
|
||||||
|
@Prop({default: {}})
|
||||||
|
core: any
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
console.log(this.core)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.core {
|
||||||
|
width: 256px;
|
||||||
|
background: #2c3e50;
|
||||||
|
height: 128px;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,20 @@
|
|||||||
|
<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>
|
@ -0,0 +1,64 @@
|
|||||||
|
function padLeftZero(str: string): string {
|
||||||
|
return ('00' + str).substr(str.length)
|
||||||
|
}
|
||||||
|
|
||||||
|
const util = {
|
||||||
|
title: function (title: string) {
|
||||||
|
window.document.title = title ? title + ' - oa' : 'veypi project'
|
||||||
|
},
|
||||||
|
getCookie(name: string) {
|
||||||
|
const reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)')
|
||||||
|
const arr = document.cookie.match(reg)
|
||||||
|
if (arr) {
|
||||||
|
return unescape(arr[2])
|
||||||
|
} else return null
|
||||||
|
},
|
||||||
|
delCookie(name: string) {
|
||||||
|
const exp = new Date()
|
||||||
|
exp.setTime(exp.getTime() - 1)
|
||||||
|
const cval = this.getCookie(name)
|
||||||
|
if (cval !== null) {
|
||||||
|
document.cookie = name + '=' + cval + ';expires=' + exp.toLocaleString()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setCookie(name: string, value: string, time: number) {
|
||||||
|
const exp = new Date()
|
||||||
|
exp.setTime(exp.getTime() + time)
|
||||||
|
document.cookie =
|
||||||
|
name + '=' + escape(value) + ';expires=' + exp.toLocaleString()
|
||||||
|
},
|
||||||
|
checkLogin() {
|
||||||
|
// return parseInt(this.getCookie('stat')) === 1
|
||||||
|
return Boolean(localStorage.auth_token)
|
||||||
|
},
|
||||||
|
|
||||||
|
formatDate(date: Date, fmt: string) {
|
||||||
|
if (/(y+)/.test(fmt)) {
|
||||||
|
fmt = fmt.replace(
|
||||||
|
RegExp.$1,
|
||||||
|
(date.getFullYear() + '').substr(4 - RegExp.$1.length)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
const o = {
|
||||||
|
'M+': date.getMonth() + 1,
|
||||||
|
'd+': date.getDate(),
|
||||||
|
'h+': date.getHours(),
|
||||||
|
'm+': date.getMinutes(),
|
||||||
|
's+': date.getSeconds()
|
||||||
|
}
|
||||||
|
for (const k in o) {
|
||||||
|
if (new RegExp(`(${k})`).test(fmt)) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
|
||||||
|
// @ts-ignore
|
||||||
|
const str = o[k] + ''
|
||||||
|
fmt = fmt.replace(
|
||||||
|
RegExp.$1,
|
||||||
|
RegExp.$1.length === 1 ? str : padLeftZero(str)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default util
|
@ -0,0 +1,2 @@
|
|||||||
|
!function(a,b,c){function d(c){var d=b.createElement("iframe"),e="https://open.work.weixin.qq.com/wwopen/sso/qrConnect?appid="+c.appid+"&agentid="+c.agentid+"&redirect_uri="+c.redirect_uri+"&state="+c.state+"&login_type=jssdk";e+=c.style?"&style="+c.style:"",e+=c.href?"&href="+c.href:"",d.src=e,d.frameBorder="0",d.allowTransparency="true",d.scrolling="no",d.width="300px",d.height="400px";var f=b.getElementById(c.id);f.innerHTML="",f.appendChild(d),d.onload=function(){d.contentWindow.postMessage&&a.addEventListener&&(a.addEventListener("message",function(b){
|
||||||
|
b.data&&b.origin.indexOf("work.weixin.qq.com")>-1&&(a.location.href=b.data)}),d.contentWindow.postMessage("ask_usePostMessage","*"))}}a.WwLogin=d}(window,document);
|
@ -0,0 +1,24 @@
|
|||||||
|
import Vue 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 OneIcon from '@veypi/one-icon'
|
||||||
|
import Message from 'vue-m-message'
|
||||||
|
import 'vue-m-message/dist/index.css'
|
||||||
|
|
||||||
|
Vue.use(Message) // will mount `Vue.prototype.$message`
|
||||||
|
|
||||||
|
// 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')
|
@ -0,0 +1,24 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
@ -0,0 +1,57 @@
|
|||||||
|
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'
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = new VueRouter({
|
||||||
|
routes
|
||||||
|
})
|
||||||
|
|
||||||
|
export default router
|
@ -0,0 +1,13 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
declare module '*.js'
|
||||||
|
declare module '*.vue' {
|
||||||
|
import Vue from 'vue'
|
||||||
|
export default Vue
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
declare module 'vuetify/lib/framework' {
|
||||||
|
import Vuetify from 'vuetify'
|
||||||
|
export default Vuetify
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import Vuex from 'vuex'
|
||||||
|
import api from '@/api'
|
||||||
|
import router from '@/router'
|
||||||
|
|
||||||
|
Vue.use(Vuex)
|
||||||
|
|
||||||
|
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)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleLogout() {
|
||||||
|
localStorage.removeItem('auth_token')
|
||||||
|
router.push({name: 'login'})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modules: {}
|
||||||
|
})
|
@ -0,0 +1,14 @@
|
|||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
<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>
|
@ -0,0 +1,50 @@
|
|||||||
|
<style>
|
||||||
|
.home {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<template>
|
||||||
|
<div class='full_size'>
|
||||||
|
<v-row no-gutters class="pa-8">
|
||||||
|
<v-col v-for="(item, key) in apps" :key="key" class="mx-4 my-2">
|
||||||
|
<AppCard :core="item"></AppCard>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang='ts'>
|
||||||
|
import {Component, Vue} from 'vue-property-decorator'
|
||||||
|
import util from '@/libs/util'
|
||||||
|
import AppCard from '@/components/app.vue'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
components: {
|
||||||
|
AppCard
|
||||||
|
}
|
||||||
|
})
|
||||||
|
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>
|
@ -0,0 +1,21 @@
|
|||||||
|
<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>
|
@ -0,0 +1,124 @@
|
|||||||
|
<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(
|
||||||
|
() => {
|
||||||
|
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>
|
@ -0,0 +1,66 @@
|
|||||||
|
<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>
|
@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "esnext",
|
||||||
|
"module": "esnext",
|
||||||
|
"strict": true,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"importHelpers": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"types": [
|
||||||
|
"webpack-env"
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"@/*": [
|
||||||
|
"src/*"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"lib": [
|
||||||
|
"esnext",
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"scripthost"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts",
|
||||||
|
"src/**/*.tsx",
|
||||||
|
"src/**/*.vue",
|
||||||
|
"tests/**/*.ts",
|
||||||
|
"tests/**/*.tsx"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
module.exports = {
|
||||||
|
transpileDependencies: [
|
||||||
|
'vuetify'
|
||||||
|
],
|
||||||
|
configureWebpack: {
|
||||||
|
output: {
|
||||||
|
filename: '[name].[hash].js'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
outputDir: '../sub/static',
|
||||||
|
devServer: {
|
||||||
|
host: '0.0.0.0',
|
||||||
|
port: 19520,
|
||||||
|
disableHostCheck: true,
|
||||||
|
proxy: {
|
||||||
|
'^/api': {
|
||||||
|
target: 'http://127.0.0.1:4001',
|
||||||
|
ws: true,
|
||||||
|
changeOrigin: true
|
||||||
|
},
|
||||||
|
'^/media': {
|
||||||
|
target: 'http://127.0.0.1:4001',
|
||||||
|
ws: true,
|
||||||
|
changeOrigin: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue