v3
veypi 11 months ago
parent 5004d00afe
commit be16fc1c5c

@ -72,32 +72,38 @@ func accessGet(x *rest.X) (any, error) {
return data, err
}
func accessPatch(x *rest.X) (any, error) {
opts := &M.AccessPatch{}
func accessDelete(x *rest.X) (any, error) {
opts := &M.AccessDelete{}
err := x.Parse(opts)
if err != nil {
return nil, err
}
data := &M.Access{}
err = cfg.DB().Where("id = ?", opts.ID).First(data).Error
if err != nil {
return nil, err
}
optsMap := make(map[string]interface{})
err = cfg.DB().Model(data).Updates(optsMap).Error
err = cfg.DB().Where("id = ?", opts.ID).Delete(data).Error
return data, err
}
func accessDelete(x *rest.X) (any, error) {
opts := &M.AccessDelete{}
func accessPatch(x *rest.X) (any, error) {
opts := &M.AccessPatch{}
err := x.Parse(opts)
if err != nil {
return nil, err
}
data := &M.Access{}
err = cfg.DB().Where("id = ?", opts.ID).Delete(data).Error
err = cfg.DB().Where("id = ?", opts.ID).First(data).Error
if err != nil {
return nil, err
}
optsMap := make(map[string]interface{})
if opts.TID != nil {
optsMap["tid"] = opts.TID
}
if opts.Level != nil {
optsMap["level"] = opts.Level
}
err = cfg.DB().Model(data).Updates(optsMap).Error
return data, err
}

@ -1,11 +1,9 @@
package user
import (
"github.com/google/uuid"
"github.com/veypi/OneBD/rest"
"oa/cfg"
M "oa/models"
"strings"
)
func useUserRole(r rest.Router) {
@ -15,43 +13,65 @@ func useUserRole(r rest.Router) {
r.Patch("/:user_role_id", userRolePatch)
r.Post("/", userRolePost)
}
func userRoleDelete(x *rest.X) (any, error) {
opts := &M.UserRoleDelete{}
func userRoleList(x *rest.X) (any, error) {
opts := &M.UserRoleList{}
err := x.Parse(opts)
if err != nil {
return nil, err
}
data := &M.UserRole{}
data := make([]*struct {
M.UserRole
Username string `json:"username"`
Nickname string `json:"nickname"`
Icon string `json:"icon"`
RoleName string `json:"role_name"`
}, 0, 10)
// data := make([]*M.UserRole, 0, 10)
err = cfg.DB().Where("id = ?", opts.ID).Delete(data).Error
query := cfg.DB().Debug().Table("user_roles").Select("user_roles.*,users.username,users.nickname,users.icon,roles.name as role_name").
Joins("JOIN users ON users.id = user_roles.user_id").
Joins("JOIN roles ON roles.id = user_roles.role_id")
if opts.UserID != nil && *opts.UserID != "-" {
query = query.Where("user_id LIKE ?", opts.UserID)
}
if opts.RoleID != nil {
query = query.Where("role_id LIKE ?", opts.RoleID)
}
if opts.AppID != nil {
query = query.Where("app_id LIKE ?", opts.AppID)
}
if opts.Status != nil {
query = query.Where("status LIKE ?", opts.Status)
}
err = query.Scan(&data).Error
return data, err
}
func userRoleGet(x *rest.X) (any, error) {
opts := &M.UserRoleGet{}
func userRolePost(x *rest.X) (any, error) {
opts := &M.UserRolePost{}
err := x.Parse(opts)
if err != nil {
return nil, err
}
data := &M.UserRole{}
err = cfg.DB().Where("id = ?", opts.ID).First(data).Error
data.UserID = opts.UserID
data.RoleID = opts.RoleID
data.AppID = opts.AppID
data.Status = opts.Status
err = cfg.DB().Create(data).Error
return data, err
}
func userRoleList(x *rest.X) (any, error) {
opts := &M.UserRoleList{}
func userRoleGet(x *rest.X) (any, error) {
opts := &M.UserRoleGet{}
err := x.Parse(opts)
if err != nil {
return nil, err
}
data := make([]*M.UserRole, 0, 10)
data := &M.UserRole{}
query := cfg.DB()
if opts.Status != nil {
query = query.Where("status LIKE ?", opts.Status)
}
err = query.Find(&data).Error
err = cfg.DB().Where("id = ?", opts.ID).First(data).Error
return data, err
}
@ -75,19 +95,15 @@ func userRolePatch(x *rest.X) (any, error) {
return data, err
}
func userRolePost(x *rest.X) (any, error) {
opts := &M.UserRolePost{}
func userRoleDelete(x *rest.X) (any, error) {
opts := &M.UserRoleDelete{}
err := x.Parse(opts)
if err != nil {
return nil, err
}
data := &M.UserRole{}
data.ID = strings.ReplaceAll(uuid.New().String(), "-", "")
data.UserID = opts.UserID
data.RoleID = opts.RoleID
data.Status = opts.Status
err = cfg.DB().Create(data).Error
err = cfg.DB().Where("id = ?", opts.ID).Delete(data).Error
return data, err
}

@ -27,7 +27,9 @@ type AccessGet struct {
}
type AccessPatch struct {
ID string `json:"id" gorm:"primaryKey;type:varchar(32)" parse:"path@access_id"`
ID string `json:"id" gorm:"primaryKey;type:varchar(32)" parse:"path@access_id"`
TID *string `json:"tid" parse:"json"`
Level *uint `json:"level" parse:"json"`
}
type AccessDelete struct {

@ -23,6 +23,6 @@ type Access struct {
Name string `json:"name" methods:"post,*list" parse:"json"`
TID string `json:"tid" methods:"post" parse:"json"`
Level uint `json:"level" methods:"post" parse:"json"`
TID string `json:"tid" methods:"post,*patch" parse:"json"`
Level uint `json:"level" methods:"post,*patch" parse:"json"`
}

@ -39,31 +39,28 @@ type UserList struct {
}
type UserRoleGet struct {
ID string `json:"id" gorm:"primaryKey;type:varchar(32)" parse:"path@user_role_id"`
UserID string `json:"user_id" parse:"path"`
ID string `json:"id" gorm:"primaryKey;type:varchar(32)" parse:"path@user_role_id"`
}
type UserRolePatch struct {
ID string `json:"id" gorm:"primaryKey;type:varchar(32)" parse:"path@user_role_id"`
Status *string `json:"status" parse:"json"`
UserID string `json:"user_id" parse:"path"`
}
type UserRoleDelete struct {
ID string `json:"id" gorm:"primaryKey;type:varchar(32)" parse:"path@user_role_id"`
UserID string `json:"user_id" parse:"path"`
RoleID string `json:"role_id" parse:"json"`
AppID string `json:"app_id" parse:"json"`
ID string `json:"id" gorm:"primaryKey;type:varchar(32)" parse:"path@user_role_id"`
}
type UserRoleList struct {
UserID *string `json:"user_id" parse:"path"`
RoleID *string `json:"role_id" parse:"query"`
AppID *string `json:"app_id" parse:"query"`
Status *string `json:"status" parse:"query"`
}
type UserRolePost struct {
Status string `json:"status" parse:"json"`
UserID string `json:"user_id" parse:"path"`
RoleID string `json:"role_id" parse:"json"`
AppID string `json:"app_id" parse:"json"`
UserID string `json:"user_id" parse:"path"`
}
type UserRoleList struct {
UserID string `json:"user_id" parse:"path"`
Status *string `json:"status" parse:"query"`
Status string `json:"status" parse:"json"`
}

@ -24,13 +24,13 @@ type User struct {
type UserRole struct {
BaseModel
UserID string `json:"user_id" methods:"get,list,post,patch,delete" parse:"path"`
UserID string `json:"user_id" methods:"*list,post" parse:"path"`
User *User `json:"-" gorm:"foreignKey:UserID;references:ID"`
RoleID string `json:"role_id" methods:"post,delete" parse:"json"`
RoleID string `json:"role_id" methods:"*list,post" parse:"json"`
Role *Role `json:"-" gorm:"foreignKey:RoleID;references:ID"`
AppID string `json:"app_id" methods:"post,delete" parse:"json"`
AppID string `json:"app_id" methods:"*list,post" parse:"json"`
App *App `json:"-" gorm:"foreignKey:AppID;references:ID"`
Status string `json:"status" methods:"post,*patch,*list" parse:"json"`

2
oaer/index.d.ts vendored

@ -1,3 +1,3 @@
export default interface OAER {
export default {
logout()
}

@ -35,7 +35,7 @@ const dirTree = (root: string | FileStat, depth = 0): HTMLElement => {
style: `padding-left: ${depth * 1 + 1}rem`,
children: [v('div', '🔤'), v('div', item.basename)],
onclick: () => {
api.token.Post({ refresh: logic.token.refresh.raw(), typ: 'ufs' }).then(e => {
api.token.Post({ refresh: logic.token.refresh.raw(), typ: 'ufs' }).then(() => {
logic.goto(fs.user.urlwrap(item.filename), undefined, true)
})

@ -133,42 +133,42 @@ const rename = (o: string, n?: string) => {
// })
// }
const get_dav = (client: webdav.WebDAVClient, base_url: string) => {
return {
client: client,
stat: client.stat,
dir: client.getDirectoryContents,
uploadstr: (dir: string, name: string, data: string) => {
if (dir.startsWith('/')) {
dir = dir.slice(1)
}
return new Promise((resolve, reject) => {
let temp = () => {
let reader = new FileReader()
reader.onload = function (event) {
var res = event.target?.result
// let data = new Blob([res])
client.putFileContents(dir + name, res).then(e => {
if (e) {
resolve(base_url + dir + name)
}
}).catch(reject)
}
reader.readAsArrayBuffer(new Blob([data], { type: 'plain/text' }))
}
client.stat(dir).then(() => {
temp()
}).catch((_) => {
client.createDirectory(dir, { recursive: true }).then(() => {
temp()
}).catch(e => {
console.warn(e)
})
})
});
}
}
}
// const get_dav = (client: webdav.WebDAVClient, base_url: string) => {
// return {
// client: client,
// stat: client.stat,
// dir: client.getDirectoryContents,
// uploadstr: (dir: string, name: string, data: string) => {
// if (dir.startsWith('/')) {
// dir = dir.slice(1)
// }
// return new Promise((resolve, reject) => {
// let temp = () => {
// let reader = new FileReader()
// reader.onload = function (event) {
// var res = event.target?.result
// // let data = new Blob([res])
// client.putFileContents(dir + name, res).then(e => {
// if (e) {
// resolve(base_url + dir + name)
// }
// }).catch(reject)
// }
// reader.readAsArrayBuffer(new Blob([data], { type: 'plain/text' }))
// }
// client.stat(dir).then(() => {
// temp()
// }).catch((_) => {
// client.createDirectory(dir, { recursive: true }).then(() => {
// temp()
// }).catch(e => {
// console.warn(e)
// })
// })
// });
// }
// }
// }
const download = (url: string) => {
return new Promise<string>((resolve, reject) => {

@ -4,8 +4,6 @@ import './style.css'
// let a = proxy.Ref(1)
// a.value++
import oaer from '../lib/main'
let code =
`eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOiI3ODA5YTZlNjhmNDE0OWM5ODFhMmFhNTI0NTE0MzIyZiIsImFpZCI6InRNUnhXejc3UDlBQk5aQTNaSXVvTlFJTGpWQkJJVWRmIiwibmFtZSI6ImFkbWluIiwiaWNvbiI6Imh0dHBzOi8vcHVibGljLnZleXBpLmNvbS9pbWcvYXZhdGFyLzAwNTEuanBnIiwiYWNjZXNzIjpudWxsLCJpc3MiOiJvYSIsImV4cCI6MTczMDk4NDY4MiwiaWF0IjoxNzMwNzI1NDgyLCJqdGkiOiIxOWZlZTc4YjQwN2M0ZTQ5OWI1Yjg2YmJjNTNjMTA2YyJ9.vIriE-L2AZLtigWXAXHrTG2_XIELqp0bAnFEBX0Hw8w`
let token = ''
let querys = window.location.search.match(/token=([^&]*)/)
if (querys && querys.length > 1) {

@ -42,11 +42,11 @@
</template>
<template v-else-if="type === 'radio'">
<div class="flex px-8 justify-between gap-4">
<template :key="ok" v-for="(ov, ok) of transDic">
<div :class="[value === ok ? 'radio-btn-active' :
'div-btn']" @click="setSelect(ok)" style="color:white;"
<template :key="ov.key" v-for="ov of transOptions">
<div :class="[value === ov.key ? 'radio-btn-active' :
'div-btn']" @click="setSelect(ov.key)" style="color:white;"
class="div-center font-bold grow truncate radio-btn rounded-md transition duration-500">
{{ ov || ok }}
{{ ov.label }}
</div>
</template>
</div>
@ -54,23 +54,32 @@
</template>
<template v-else-if="type === 'select'">
<div class="noborder cursor-pointer w-full overflow-x-auto whitespace-nowrap" @click="showSelect"
:title="title">
<span v-if="value === undefined || value === null"></span>
<span v-else-if="!Array.isArray(value)">{{ transDic[value] || value }}</span>
<div class="noborder cursor-pointer w-full overflow-x-auto whitespace-nowrap" @click="showSelect">
<span v-if="!value">
<div v-if="typeof selectNone === 'string'">{{ selectNone }}</div>
<div v-else></div>
</span>
<div v-else-if="!Array.isArray(value)">
<slot name="select-item" :value="transDic[value]">
{{ transDic[value].label }}
</slot>
</div>
<template v-else>
<span class="mx-2" v-for=" iv in value " :key="iv">{{ transDic[iv] || iv }}</span>
<div class="mx-2" v-for=" iv in value " :key="iv">
<slot name="select-item" :value="transDic[iv]">
{{ transDic[iv].label }}
</slot>
</div>
</template>
</div>
<div @mouseleave="showSelectOpt = false"
:style="{ left: selectPos[0] + 'px', top: selectPos[1] + 'px', height: showSelectOpt ? '20rem' : '0rem' }"
class="select-opt text-base text-white rounded-md overflow-y-auto" style="min-width: 10rem;" :title="title">
<div class="m-2 p-2" v-if="!options"></div>
class="select-opt text-base text-white rounded-md overflow-y-auto" style="min-width: 10rem;">
<div class="m-2 p-2" v-if="!transOptions.length"></div>
<div :class="[ov.key === value ? 'bg-gray-500' : 'bg-gray-800']" class="cursor-pointer m-2 p-2 rounded-md
hover:bg-gray-500" @click="setSelect(ov.key)" v-for="ov of options" :key="ov.key">
{{ ov.name }}
hover:bg-gray-500" @click="setSelect(ov.key)" v-for="ov of transOptions" :key="ov.key">
{{ ov.label }}
</div>
<div class="w-full h-32"></div>
</div>
</template>
<template v-else-if="type === 'region'">
@ -122,6 +131,7 @@
</div>
</template>
<script lang="ts" setup>
import { OneIcon } from '@veypi/one-icon'
@ -144,10 +154,16 @@ type ArgType = 'text' | 'password' | 'bool' | 'select' | 'radio' | 'number' | 'r
// [ArgType.Bool]: '',
// }
type NumberOptions = {
max?: number
min?: number
}
type SelectBaseOption = { key: string, label: string, [key: string]: any }
type SelectOptions = SelectBaseOption[] | string[] | { [key: string]: SelectBaseOption | string }
const props = withDefaults(defineProps<{
modelValue?: any
type?: ArgType,
options?: any,
disabled?: boolean
hideBorder?: boolean
tidy?: boolean
@ -158,7 +174,16 @@ const props = withDefaults(defineProps<{
require?: boolean
clicktoedit?: boolean,
normalwrap?: (s: string) => string
// /^reg for value &/
validate?: any
// work for select radio number
// number: { max: 100, min: 0 }
// select: [{ key: 'a', label: 'A' }]
options?: NumberOptions | SelectOptions
selectNone?: any
selectSearch?: any
//
title?: string
}>(), {
@ -187,7 +212,8 @@ const dy_style = computed(() => `text-align:${props.align}`)
let inputRef = ref<HTMLInputElement>()
let all = ref<HTMLElement>()
const transDic = ref({} as { [key: string]: string })
const transOptions = ref<SelectBaseOption[]>([])
const transDic = ref<{ [key: string]: SelectBaseOption }>({})
const change = (s: string) => {
if (props.disabled) {
@ -219,20 +245,31 @@ const sync = () => {
}
if (props.type === 'radio' || props.type === 'select') {
transDic.value = {}
if (Array.isArray(props.options)) {
for (let i of props.options) {
transOptions.value = []
let options = props.options as SelectOptions
if (Array.isArray(options)) {
for (let i of options) {
if (typeof i === 'string') {
transDic.value[i] = i
transOptions.value.push({ key: i, label: i })
} else {
transDic.value[i.key] = i.name
transOptions.value.push({ key: i.key, label: i.label })
}
}
// console.log(transDic.value)
} else {
for (let i in props.options) {
transDic.value[i] = props.options[i]
for (let i in options) {
let v = options[i]
if (typeof v === 'string') {
transOptions.value.push({ key: i, label: v })
} else {
transOptions.value.push(v)
}
}
}
for (let i of transOptions.value) {
transDic.value[i.key] = i
}
console.log(transDic.value)
}
}
watch(computed(() => props), sync)
@ -242,10 +279,11 @@ const check = (e?: InputEvent) => {
if (v !== 0 && !v) {
return false
}
if (typeof props.options?.max === 'number' && v > props.options.max) {
let options = props.options as NumberOptions
if (typeof options?.max === 'number' && v > options.max) {
return false
}
if (typeof props.options?.min === 'number' && v < props.options.min) {
if (typeof options?.min === 'number' && v < options.min) {
return false
}
value.value = v
@ -422,7 +460,7 @@ select {
top: 0;
background: #333;
transform-origin: top;
transition: height 0.3s linear;
transition: height 3s linear;
}
.radio-btn {

@ -36,11 +36,16 @@ export function Get(access_id: string) {
return webapi.Get<models.Access>(`/access/${access_id}`, {})
}
export function Patch(access_id: string) {
return webapi.Patch<models.Access>(`/access/${access_id}`, {})
export function Patch(access_id: string, json: PatchOpts) {
return webapi.Patch<models.Access>(`/access/${access_id}`, { json })
}
export function Delete(access_id: string) {
return webapi.Delete<models.Access>(`/access/${access_id}`, {})
}
// keep
export interface PatchOpts {
tid?: string
level?: number
}

@ -111,3 +111,34 @@ export function ResourcePost(app_id: string, json: ResourcePostOpts) {
return webapi.Post<models.Resource>(`/app/${app_id}/resource`, { json })
}
export function RoleGet(app_id: string, role_id: string) {
return webapi.Get<models.Role>(`/app/${app_id}/role/${role_id}`, {})
}
export interface RolePatchOpts {
name?: string
des?: string
}
export function RolePatch(app_id: string, role_id: string, json: RolePatchOpts) {
return webapi.Patch<models.Role>(`/app/${app_id}/role/${role_id}`, { json })
}
export function RoleDelete(app_id: string, role_id: string) {
return webapi.Delete<models.Role>(`/app/${app_id}/role/${role_id}`, {})
}
export interface RoleListQuery {
name?: string
}
export function RoleList(app_id: string, query: RoleListQuery) {
return webapi.Get<models.Role[]>(`/app/${app_id}/role`, { query })
}
export interface RolePostOpts {
name: string
des: string
}
export function RolePost(app_id: string, json: RolePostOpts) {
return webapi.Post<models.Role>(`/app/${app_id}/role`, { json })
}

@ -1,7 +1,6 @@
import * as user from "./user"
import * as token from "./token"
import * as role from "./role"
import * as app from "./app"
import * as access from "./access"
import { token as apitoken } from './webapi'
@ -10,7 +9,6 @@ export default {
apitoken,
user,
token,
role,
app,
access
}

@ -85,5 +85,9 @@ export interface UserRole {
role_id: string
app_id: string
status: string
username?: string
nickname?: string
icon?: string
role_name?: string
}

@ -1,42 +0,0 @@
//
// Copyright (C) 2024 veypi <i@veypi.com>
// 2024-10-11 14:36:07
// Distributed under terms of the MIT license.
//
import webapi from "./webapi"
import * as models from "./models"
export function Get(role_id: string) {
return webapi.Get<models.Role>(`/role/${role_id}`, {})
}
export interface PatchOpts {
name?: string
des?: string
app_id?: string
}
export function Patch(role_id: string, json: PatchOpts) {
return webapi.Patch<models.Role>(`/role/${role_id}`, { json })
}
export function Delete(role_id: string) {
return webapi.Delete<models.Role>(`/role/${role_id}`, {})
}
export interface PostOpts {
name: string
des: string
app_id: string
}
export function Post(json: PostOpts) {
return webapi.Post<models.Role>(`/role`, { json })
}
export interface ListQuery {
name?: string
}
export function List(query: ListQuery) {
return webapi.Get<models.Role[]>(`/role`, { query })
}

@ -65,8 +65,8 @@ export interface UserRoleDeleteOpts {
role_id: string
app_id: string
}
export function UserRoleDelete(user_id: string, user_role_id: string, json: UserRoleDeleteOpts) {
return webapi.Delete<models.UserRole>(`/user/${user_id}/user_role/${user_role_id}`, { json })
export function UserRoleDelete(user_id: string, user_role_id: string) {
return webapi.Delete<models.UserRole>(`/user/${user_id}/user_role/${user_role_id}`, {})
}
export interface UserRolePostOpts {
@ -80,6 +80,8 @@ export function UserRolePost(user_id: string, json: UserRolePostOpts) {
export interface UserRoleListQuery {
status?: string
role_id?: string
app_id?: string
}
export function UserRoleList(user_id: string, query: UserRoleListQuery) {
return webapi.Get<models.UserRole[]>(`/user/${user_id}/user_role`, { query })

@ -19,9 +19,6 @@ const util = {
}
},
datetostr(d: string) {
if (!d.endsWith('Z')) {
d = d + 'Z'
}
let r = new Date(d)
let delta = (new Date().getTime() - r.getTime()) / 1000
if (delta < 0) {
@ -40,7 +37,7 @@ const util = {
goto(url: string) {
window.open(url, '_blank')
},
title: function(title: string) {
title: function (title: string) {
window.document.title = title ? title + ' - oa' : 'veypi project'
},
getCookie(name: string) {

@ -6,13 +6,13 @@
-->
<template>
<div>
<div class="flex justify-start items-center gap-4">
<div class="flex justify-start items-center gap-4 mb-8">
<img class="w-12 h-12 rounded-full" :src="core.icon">
<div class="text-3xl">
{{ core.name }}
</div>
</div>
<NuxtPage keepalive :core='core' :page-key="route => route.fullPath"></NuxtPage>
<NuxtPage keepalive :page-key="route => route.fullPath"></NuxtPage>
</div>
</template>
@ -29,6 +29,8 @@ const router = useRouter()
let menu = useMenuStore()
let core = ref({} as models.App)
provide('app', core)
const set_menu = () => {
let p = '/app/' + core.value.id
menu.set([

@ -11,23 +11,22 @@
<div @click="created(0)"></div>
</div>
<div class="w-full">
<crud vertical :keys="role_keys" :data="role" @update="update(0,
$event)">
<template #k_created="{ value }">{{ util.datetostr(value) }}</template>
<crud vertical :keys="role_keys" :data="role" @update="update($event, role, api.app.RolePatch, app.id)">
<template #k_created_at="{ value }">{{ util.datetostr(value) }}</template>
<template #k__="{ row }">
<div color="primary" size="sm" @click="show_dialog(0,
row.id)">权限</div>
<div color="secondary" size="sm" @click="show_dialog(1,
row.id)">用户</div>
<div color="negative" size="sm" @click="del(0, row.id)">删除</div>
<template v-if="row.id === app.role_id">
<template v-if="row.id === app.init_role_id">
<div color="positive" disable size="sm">初始角色</div>
</template>
<template v-else>
<div size="sm" @click="api.app.update(app.id, {
role_id:
<div size="sm" @click="api.app.Patch(app.id, {
init_role_id:
row.id
}).then(_ => app.role_id = row.id)">设置为初始角色</div>
}).then(_ => app.init_role_id = row.id)">设置为初始角色</div>
</template>
</template>
</crud>
@ -38,52 +37,49 @@
<div @click="created(1)"></div>
</div>
<div class="w-full">
<crud vertical :keys="resource_keys" :data="resource" @update="update(1,
$event)">
<template #k_created="{ value }">{{ util.datetostr(value) }}</template>
<crud vertical :keys="resource_keys" :data="resource"
@update="update($event, resource, api.app.ResourcePatch, app.id)">
<template #k_created_at="{ value }">{{ util.datetostr(value) }}</template>
<template #k__="{ row }">
<div color="negative" size="sm" @click="del(1, row.name)">删除</div>
</template>
</crud>
</div>
<q-dialog v-model="dialog">
<q-card v-if="dialog_obj" class="mx-4 mt-4" style="width: 1000px;max-width: 90vw;">
<q-card-section class="row items-center q-pb-none">
<div class="text-h6">{{ dialog_obj.name }}
<UModal v-model="dialog" :ui="{ 'width': '' }">
<UCard v-if="dialog_obj" style="width: 1000px;max-width: 90vw;">
<template #header>
<div class="items-center flex">
<div class="text-2xl">{{ dialog_obj.name }}
</div>
<div class="flex-grow"></div>
<div v-if="dialog_mode">
<vinput :model-value="''" type="select" :options="['1', '2']" select-none=""></vinput>
<!-- <USelect filled :model-value="''" @update:model-value="roleuser.add" use-input hide-selected fill-input -->
<!-- input-debounce="0" label="添加用户" :options="users_cache" @filter="filterFn" style="width: 20rem"> -->
<!-- </USelect> -->
</div>
<div v-else @click="created(2, { role_id: dialog_obj.id })">添加权限</div>
</div>
<q-space />
<div v-if="dialog_mode">
<q-select filled :model-value="''" @update:model-value="roleuser.add" use-input hide-selected fill-input
input-debounce="0" label="添加用户" :options="users_cache" @filter="filterFn" style="width: 20rem">
<template v-slot:no-option>
<q-item>
<q-item-section class="text-grey">
无结果
</q-item-section>
</q-item>
</template>
</q-select>
</div>
<div v-else @click="created(2, { role_id: dialog_obj.id })">添加权限</div>
</q-card-section>
</template>
<q-card-section v-if="dialog_mode">
<div v-if="dialog_mode">
<crud vertical :keys="users_keys" :data="users">
<template #k__="{ row }">
<div color="negative" size="sm" @click="roleuser.drop(row)"></div>
</template>
</crud>
</q-card-section>
<q-card-section v-else>
<crud vertical :keys="access_keys" :data="access" @update="update(2, $event)">
</div>
<div v-else>
<crud vertical :keys="access_keys" :data="access" @update="update($event, access, api.access.Patch)">
<template #k__="{ row }">
<div color="negative" size="sm" @click="del(2, row.id)">删除</div>
</template>
</crud>
</q-card-section>
</q-card>
</q-dialog>
</div>
</UCard>
</UModal>
</div>
</template>
@ -101,7 +97,7 @@ const role_keys = ref<any>([
},
{ name: 'name', label: '标识符' },
{ name: 'des', label: '描述', editable: true },
{ name: 'created', label: '创建时间' },
{ name: 'created_at', label: '创建时间' },
{ name: 'user_count', label: '绑定用户数' },
{
name: '_', label: '操作', style: { 'justify-content': 'start' },
@ -111,7 +107,7 @@ const role_keys = ref<any>([
const resource_keys = ref<any>([
{ name: 'name', label: '标识符' },
{ name: 'des', label: '描述', editable: true },
{ name: 'created', label: '创建时间' },
{ name: 'created_at', label: '创建时间' },
{
name: '_', label: '操作', style: { 'justify-content': 'start' },
width: 40
@ -141,11 +137,12 @@ const users_keys = ref<any>([
])
let access = ref<models.Access[]>([])
let users = ref<models.User[]>([])
let users = ref<models.UserRole[]>([])
let users_cache = ref<any[]>([])
const resource = ref<any[]>([])
const role = ref<any[]>([])
const app = inject('app') as Ref<models.App>
watch(computed(() => app.value.id), (v) => {
sync(v)
@ -155,13 +152,10 @@ const sync = (id: any) => {
if (!id) {
return
}
api.role.List(id).then(e => {
api.app.RoleList(id, {}).then(e => {
role.value = e
})
api.role(id).list().then(e => {
role.value = e
})
api.resource(id).list().then(e => {
api.app.ResourceList(id).then(e => {
resource.value = e
})
}
@ -171,11 +165,12 @@ const show_dialog = (mode: number, idx: string) => {
dialog.value = true
dialog_mode.value = mode
if (mode) {
api.user.list({ role_id: idx }).then(e => {
api.user.UserRoleList('-', { role_id: idx }).then(e => {
console.log(e)
users.value = e
})
} else {
api.access(app.value.id).list({ role_id: idx }).then(e => {
api.access.List({ app_id: app.value.id, role_id: idx }).then(e => {
access.value = e
})
}
@ -184,7 +179,7 @@ const show_dialog = (mode: number, idx: string) => {
// 0: role 1: resource 2: access 3: users
const crud_option = (mode: number) => {
let res = {
api: api.role(app.value.id),
api: api.app.RolePatch(app.value.id),
lable: '角色',
obj: role,
}
@ -220,32 +215,36 @@ const created = (k: number, props?: any) => {
})
}
}
$q.dialog({
title: '创建' + opt.lable,
message: '请输入标识码',
prompt: prompt as any,
options: options as any,
cancel: true,
persistent: true
}).onOk(data => {
opt.api.create(data, props).then(e => {
msg.Info('创建成功')
opt.obj.value.push(e)
}).catch(e => {
msg.Warn('创建失败: ' + e)
})
})
// $q.dialog({
// title: '' + opt.lable,
// message: '',
// prompt: prompt as any,
// options: options as any,
// cancel: true,
// persistent: true
// }).onOk(data => {
// opt.api.create(data, props).then(e => {
// msg.Info('')
// opt.obj.value.push(e)
// }).catch(e => {
// msg.Warn(' ' + e)
// })
// })
}
const update = (k: number, props: any[]) => {
let opt = crud_option(k)
console.log(props)
const update = (props: any[], objs: any, cb: any, topid?: string) => {
// let opt = crud_option(k)
let patch = cb
if (topid) {
patch = (id: string, props: any) => {
return cb(topid, id, props)
}
}
for (let i in props) {
let id = opt.obj.value[i][k === 1 ? 'name' : 'id']
console.log(id)
opt.api.update(id, props[i]).then(() => {
Object.assign(opt.obj.value[i], props[i])
}).catch(e => {
let id = objs[i].id
patch(id, props[i]).then(() => {
Object.assign(objs[i], props[i])
}).catch((e: any) => {
msg.Warn('更新失败: ' + e)
})
}
@ -294,7 +293,7 @@ const filterFn = (val: string, cb: any) => {
cb(() => {
users_cache.value = e.map(i => {
return Object.assign({
label: i.username,
name: i.username,
value: i.id,
}, i)
})

@ -56,19 +56,15 @@ const keys = ref<any>([
{ name: 'init_url', label: '项目首页', validate: /^(https?:\/\/)?(([\da-z\.-]+)|(\d{1,3}(\.\d{1,3}){3}))(:\d+)?([\/\w \.-]*)*\/?$/ },
{ name: 'redirect', label: '跳转地址' },
])
let props = withDefaults(defineProps<{
core: models.App,
}>(),
{}
)
const core = inject('app') as Ref<models.App>
const newApp = ref({})
const table = ref()
const save = () => {
api.app.Patch(props.core.id, newApp.value).then(e => {
api.app.Patch(core.value.id, newApp.value).then(e => {
msg.Info('更新成功')
Object.assign(props.core, newApp.value)
Object.assign(core, newApp.value)
newApp.value = {}
}).catch(e => {
msg.Warn('更新失败 ' + e)
@ -78,8 +74,8 @@ const save = () => {
const tmpkey = ref('')
const getkey = () => {
msg.Prompt('请输入应用名确认', '').then((s) => {
if (s === props.core.name) {
api.app.Key(props.core.id).then(e => {
if (s === core.value.name) {
api.app.Key(core.value.id).then(e => {
tmpkey.value = e
navigator.clipboard.writeText(e)
.then(() => {

@ -6,7 +6,7 @@
-->
<template>
<div>
<Editor style="" v-if="core.id" :eid="core.id + '.des'" v-model="preview_mode" :content="content" @save="save">
<Editor style="" v-if="app.id" :eid="app.id + '.des'" v-model="preview_mode" :content="content" @save="save">
</Editor>
</div>
</template>
@ -16,36 +16,31 @@ import type { models } from '#imports';
import { fs } from '@veypi/oaer'
let props = withDefaults(defineProps<{
core: models.App,
}>(),
{}
)
const app = inject('app') as Ref<models.App>
let preview_mode = ref(true)
let content = ref('')
const sync = () => {
if (props.core.des) {
fs.app.getFileContents(fs.app.urlunwrap(props.core.des), { format: 'text' }).then((e) => {
if (app.value.des) {
fs.app.getFileContents(fs.app.urlunwrap(app.value.des), { format: 'text' }).then((e) => {
content.value = e as string
})
}
}
watch(computed(() => props.core.id), () => {
watch(computed(() => app.value.id), () => {
sync()
}, { immediate: true })
const save = (des: string) => {
let furl = `/info/appdes/${props.core.id}.md`
let furl = `/info/appdes/${app.value.id}.md`
fs.app.putFileContents(furl, des).then((e) => {
furl = fs.app.urlwrap(furl)
if (props.core.des !== furl) {
api.app.Patch(props.core.id, { des: furl }).then((e) => {
if (app.value.des !== furl) {
api.app.Patch(app.value.id, { des: furl }).then((e) => {
preview_mode.value = true
props.core.des = furl
app.value.des = furl
})
} else {
preview_mode.value = true

Loading…
Cancel
Save