mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2025-05-11 02:15:48 +02:00
[frontend-next] bug fix
This commit is contained in:
parent
2a13103186
commit
070c53b0b2
26 changed files with 414 additions and 345 deletions
|
@ -1,2 +1 @@
|
|||
VITE_API_ROOT = /api
|
||||
VITE_API_WSS_ROOT = wss://nginx.jackyu.cn/api
|
||||
|
|
|
@ -1,2 +1 @@
|
|||
VUE_APP_API_ROOT = /api
|
||||
VUE_APP_API_WSS_ROOT = /api
|
||||
VITE_API_ROOT = /api
|
||||
|
|
|
@ -4,5 +4,5 @@ import (
|
|||
"embed"
|
||||
)
|
||||
|
||||
//go:embed dist
|
||||
//go:embed dist/* dist/*/*
|
||||
var DistFS embed.FS
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img"
|
||||
class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257">
|
||||
<defs>
|
||||
<linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%">
|
||||
<stop offset="0%" stop-color="#41D1FF"></stop>
|
||||
<stop offset="100%" stop-color="#BD34FE"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%">
|
||||
<stop offset="0%" stop-color="#FFEA83"></stop>
|
||||
<stop offset="8.333%" stop-color="#FFDD35"></stop>
|
||||
<stop offset="100%" stop-color="#FFA800"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path fill="url(#IconifyId1813088fe1fbc01fb466)"
|
||||
d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path>
|
||||
<path fill="url(#IconifyId1813088fe1fbc01fb467)"
|
||||
d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.6 KiB |
|
@ -1,8 +1,19 @@
|
|||
<script setup lang="ts">
|
||||
import {useGettext} from 'vue3-gettext'
|
||||
|
||||
const {pagination, size} = defineProps(['pagination', 'size'])
|
||||
const emit = defineEmits(['changePage'])
|
||||
const {$gettext} = useGettext()
|
||||
|
||||
function changePage(num: number) {
|
||||
emit('changePage', num)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="Object.keys(pagination).length !== 0">
|
||||
<div v-if="pagination.total>pagination.per_page">
|
||||
<a-pagination
|
||||
:current="pagination.current_page"
|
||||
:hideOnSinglePage="true"
|
||||
:pageSize="pagination.per_page"
|
||||
:size="size"
|
||||
:total="pagination.total"
|
||||
|
@ -10,27 +21,9 @@
|
|||
class="pagination"
|
||||
@change="changePage"
|
||||
/>
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'StdPagination',
|
||||
props: {
|
||||
pagination: Object,
|
||||
size: {
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changePage(num) {
|
||||
return this.$emit('changePage', num)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.ant-pagination-total-text {
|
||||
@media (max-width: 450px) {
|
||||
|
|
|
@ -5,7 +5,7 @@ const {$gettext, interpolate} = gettext
|
|||
|
||||
import StdDataEntry from '@/components/StdDataEntry'
|
||||
import StdPagination from './StdPagination.vue'
|
||||
import {nextTick, reactive, ref} from 'vue'
|
||||
import {nextTick, reactive, ref, watch} from 'vue'
|
||||
import {useRoute, useRouter} from 'vue-router'
|
||||
import {message} from 'ant-design-vue'
|
||||
|
||||
|
@ -61,9 +61,9 @@ const props = defineProps({
|
|||
})
|
||||
|
||||
|
||||
const data_source = reactive([])
|
||||
const data_source = ref([])
|
||||
const loading = ref(true)
|
||||
const pagination = ({
|
||||
const pagination = reactive({
|
||||
total: 1,
|
||||
per_page: 10,
|
||||
current_page: 1,
|
||||
|
@ -80,7 +80,6 @@ const rowSelection = reactive({})
|
|||
const searchColumns = getSearchColumns()
|
||||
const pithyColumns = getPithyColumns()
|
||||
|
||||
|
||||
get_list()
|
||||
|
||||
defineExpose({
|
||||
|
@ -102,7 +101,7 @@ function get_list(page_num = null) {
|
|||
params['page'] = page_num
|
||||
}
|
||||
props.api!.get_list(params).then((r: any) => {
|
||||
Object.assign(data_source, r.data)
|
||||
data_source.value = r.data
|
||||
|
||||
if (r.pagination !== undefined) {
|
||||
Object.assign(pagination, r.pagination)
|
||||
|
@ -161,10 +160,17 @@ function onSelect(record: any) {
|
|||
const router = useRouter()
|
||||
|
||||
const reset_search = async () => {
|
||||
params = reactive({})
|
||||
Object.keys(params).forEach(v => {
|
||||
delete params[v]
|
||||
})
|
||||
router.push({query: {}}).catch(() => {
|
||||
})
|
||||
}
|
||||
|
||||
watch(params, () => {
|
||||
router.push({query: params})
|
||||
get_list()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -212,7 +218,6 @@ const reset_search = async () => {
|
|||
</template>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
</a-table>
|
||||
<std-pagination :pagination="pagination" @changePage="get_list"/>
|
||||
</div>
|
||||
|
|
|
@ -1 +1,5 @@
|
|||
@import "ant-design-vue/dist/antd.dark";
|
||||
|
||||
.directive-editor-extra {
|
||||
background-color: rgba(0, 0, 0, 0.84) !important;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import {createPinia} from 'pinia'
|
|||
import gettext from './gettext'
|
||||
import App from './App.vue'
|
||||
import router from './routes'
|
||||
import 'ant-design-vue/dist/antd.less'
|
||||
//import 'ant-design-vue/dist/antd.less'
|
||||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
|
||||
import {useSettingsStore} from '@/pinia'
|
||||
|
||||
|
|
|
@ -1,3 +1 @@
|
|||
@import "ant-design-vue/dist/antd.variable";
|
||||
|
||||
@border-radius-base: 4px;
|
||||
@import 'ant-design-vue/dist/antd.less';
|
||||
|
|
|
@ -1,44 +1,42 @@
|
|||
<script setup lang="ts">
|
||||
import CertInfo from '@/views/domain/cert/CertInfo.vue'
|
||||
import IssueCert from '@/views/domain/cert/IssueCert.vue'
|
||||
import {computed, ref} from 'vue'
|
||||
|
||||
const {directivesMap, current_server_directives, enabled} = defineProps<{
|
||||
directivesMap: any
|
||||
current_server_directives: Array<any>
|
||||
enabled: boolean
|
||||
}>()
|
||||
|
||||
const info = ref(null)
|
||||
|
||||
interface Info {
|
||||
get(): void
|
||||
}
|
||||
|
||||
function callback() {
|
||||
const t: Info | null = info.value
|
||||
t!.get()
|
||||
}
|
||||
|
||||
const name = computed(() => {
|
||||
return directivesMap['server_name'][0].params.trim()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<cert-info ref="info" :domain="name" v-if="name"/>
|
||||
<issue-cert
|
||||
:current_server_directives="current_server_directives"
|
||||
:directives-map="directivesMap"
|
||||
v-model="auto_cert"
|
||||
v-model:enabled="enabled"
|
||||
@callback="callback"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CertInfo from '@/views/domain/cert/CertInfo'
|
||||
import IssueCert from '@/views/domain/cert/IssueCert'
|
||||
|
||||
export default {
|
||||
name: 'Cert',
|
||||
components: {IssueCert, CertInfo},
|
||||
props: {
|
||||
directivesMap: Object,
|
||||
current_server_directives: Array,
|
||||
auto_cert: Boolean
|
||||
},
|
||||
model: {
|
||||
prop: 'auto_cert',
|
||||
event: 'change_auto_cert'
|
||||
},
|
||||
methods: {
|
||||
callback() {
|
||||
this.$refs.info.get()
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
name() {
|
||||
return this.directivesMap['server_name'][0].params.trim()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
|
|
|
@ -19,6 +19,10 @@ function get() {
|
|||
ok.value = false
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
get
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -1,9 +1,123 @@
|
|||
<script setup lang="ts">
|
||||
import {issue_cert} from '../methods'
|
||||
import {useGettext} from 'vue3-gettext'
|
||||
import {computed, nextTick, ref, watch} from 'vue'
|
||||
import {message} from 'ant-design-vue'
|
||||
import domain from '@/api/domain'
|
||||
|
||||
const {$gettext, interpolate} = useGettext()
|
||||
|
||||
const {directivesMap, current_server_directives, enabled} = defineProps<{
|
||||
directivesMap: any
|
||||
current_server_directives: Array<any>
|
||||
enabled: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits(['changeEnabled', 'callback', 'update:enabled'])
|
||||
|
||||
const issuing_cert = ref(false)
|
||||
|
||||
function onchange(r: boolean) {
|
||||
emit('changeEnabled', r)
|
||||
change_auto_cert(r)
|
||||
if (r) {
|
||||
job()
|
||||
}
|
||||
}
|
||||
|
||||
function job() {
|
||||
issuing_cert.value = true
|
||||
|
||||
if (no_server_name.value) {
|
||||
message.error($gettext('server_name not found in directives'))
|
||||
issuing_cert.value = false
|
||||
return
|
||||
}
|
||||
|
||||
if (server_name_more_than_one.value) {
|
||||
message.error($gettext('server_name parameters more than one'))
|
||||
issuing_cert.value = false
|
||||
return
|
||||
}
|
||||
|
||||
const server_name = directivesMap['server_name'][0]
|
||||
|
||||
if (!directivesMap['ssl_certificate']) {
|
||||
current_server_directives.splice(server_name.idx + 1, 0, {
|
||||
directive: 'ssl_certificate',
|
||||
params: ''
|
||||
})
|
||||
}
|
||||
|
||||
nextTick(() => {
|
||||
if (!directivesMap['ssl_certificate_key']) {
|
||||
const ssl_certificate = directivesMap['ssl_certificate'][0]
|
||||
current_server_directives.splice(ssl_certificate.idx + 1, 0, {
|
||||
directive: 'ssl_certificate_key',
|
||||
params: ''
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
setTimeout(() => {
|
||||
issue_cert(name.value, callback)
|
||||
}, 100)
|
||||
}
|
||||
|
||||
function callback(ssl_certificate: string, ssl_certificate_key: string) {
|
||||
directivesMap['ssl_certificate'][0]['params'] = ssl_certificate
|
||||
directivesMap['ssl_certificate_key'][0]['params'] = ssl_certificate_key
|
||||
|
||||
issuing_cert.value = false
|
||||
emit('callback')
|
||||
}
|
||||
|
||||
function change_auto_cert(r: boolean) {
|
||||
if (r) {
|
||||
domain.add_auto_cert(name.value).then(() => {
|
||||
message.success(interpolate($gettext('Auto-renewal enabled for %{name}'), {name: name.value}))
|
||||
}).catch(e => {
|
||||
message.error(e.message ?? interpolate($gettext('Enable auto-renewal failed for %{name}'), {name: name.value}))
|
||||
})
|
||||
} else {
|
||||
domain.remove_auto_cert(name.value).then(() => {
|
||||
message.success(interpolate($gettext('Auto-renewal disabled for %{name}'), {name: name.value}))
|
||||
}).catch(e => {
|
||||
message.error(e.message ?? interpolate($gettext('Disable auto-renewal failed for %{name}'), {name: name.value}))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const server_name_more_than_one = computed(() => {
|
||||
return directivesMap['server_name'] && (directivesMap['server_name'].length > 1 ||
|
||||
directivesMap['server_name'][0].params.trim().indexOf(' ') > 0)
|
||||
})
|
||||
|
||||
const no_server_name = computed(() => {
|
||||
return directivesMap['server_name'].length === 0
|
||||
})
|
||||
|
||||
const name = computed(() => {
|
||||
return directivesMap['server_name'][0].params.trim()
|
||||
})
|
||||
|
||||
watch(server_name_more_than_one, () => {
|
||||
emit('update:enabled', false)
|
||||
onchange(false)
|
||||
})
|
||||
|
||||
watch(no_server_name, () => {
|
||||
emit('update:enabled', false)
|
||||
onchange(false)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<a-form-item :label="$gettext('Encrypt website with Let\'s Encrypt')">
|
||||
<a-switch
|
||||
:loading="issuing_cert"
|
||||
v-model="M_enabled"
|
||||
v-model:checked="enabled"
|
||||
@change="onchange"
|
||||
:disabled="no_server_name||server_name_more_than_one"
|
||||
/>
|
||||
|
@ -27,7 +141,7 @@
|
|||
Note: The server_name in the current configuration must be the domain name
|
||||
you need to get the certificate.
|
||||
</p>
|
||||
<p v-if="enabled" v-translate>
|
||||
<p v-translate>
|
||||
The certificate for the domain will be checked every hour,
|
||||
and will be renewed if it has been more than 1 month since it was last issued.
|
||||
</p>
|
||||
|
@ -38,123 +152,6 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {issue_cert} from '@/views/domain/methods'
|
||||
import $gettext, {$interpolate} from '@/lib/translate/gettext'
|
||||
|
||||
export default {
|
||||
name: 'IssueCert',
|
||||
props: {
|
||||
directivesMap: Object,
|
||||
current_server_directives: Array,
|
||||
enabled: Boolean
|
||||
},
|
||||
model: {
|
||||
prop: 'enabled',
|
||||
event: 'changeEnabled'
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
issuing_cert: false,
|
||||
M_enabled: this.enabled,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onchange(r) {
|
||||
this.$emit('changeEnabled', r)
|
||||
this.change_auto_cert(r)
|
||||
if (r) {
|
||||
this.job()
|
||||
}
|
||||
},
|
||||
job() {
|
||||
this.issuing_cert = true
|
||||
|
||||
if (this.no_server_name) {
|
||||
this.$message.error($gettext('server_name not found in directives'))
|
||||
this.issuing_cert = false
|
||||
return
|
||||
}
|
||||
|
||||
if (this.server_name_more_than_one) {
|
||||
this.$message.error($gettext('server_name parameters more than one'))
|
||||
this.issuing_cert = false
|
||||
return
|
||||
}
|
||||
|
||||
const server_name = this.directivesMap['server_name'][0]
|
||||
|
||||
if (!this.directivesMap['ssl_certificate']) {
|
||||
this.current_server_directives.splice(server_name.idx + 1, 0, {
|
||||
directive: 'ssl_certificate',
|
||||
params: ''
|
||||
})
|
||||
}
|
||||
|
||||
this.$nextTick(() => {
|
||||
if (!this.directivesMap['ssl_certificate_key']) {
|
||||
const ssl_certificate = this.directivesMap['ssl_certificate'][0]
|
||||
this.current_server_directives.splice(ssl_certificate.idx + 1, 0, {
|
||||
directive: 'ssl_certificate_key',
|
||||
params: ''
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
setTimeout(() => {
|
||||
issue_cert(this.name, this.callback)
|
||||
}, 100)
|
||||
},
|
||||
callback(ssl_certificate, ssl_certificate_key) {
|
||||
this.$set(this.directivesMap['ssl_certificate'][0], 'params', ssl_certificate)
|
||||
this.$set(this.directivesMap['ssl_certificate_key'][0], 'params', ssl_certificate_key)
|
||||
this.issuing_cert = false
|
||||
this.$emit('callback')
|
||||
},
|
||||
change_auto_cert(r) {
|
||||
if (r) {
|
||||
this.$api.domain.add_auto_cert(this.name).then(() => {
|
||||
this.$message.success($interpolate($gettext('Auto-renewal enabled for %{name}'), {name: this.name}))
|
||||
}).catch(e => {
|
||||
this.$message.error(e.message ?? $interpolate($gettext('Enable auto-renewal failed for %{name}'), {name: this.name}))
|
||||
})
|
||||
} else {
|
||||
this.$api.domain.remove_auto_cert(this.name).then(() => {
|
||||
this.$message.success($interpolate($gettext('Auto-renewal disabled for %{name}'), {name: this.name}))
|
||||
}).catch(e => {
|
||||
this.$message.error(e.message ?? $interpolate($gettext('Disable auto-renewal failed for %{name}'), {name: this.name}))
|
||||
})
|
||||
}
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
server_name_more_than_one() {
|
||||
this.M_enabled = false
|
||||
this.onchange(false)
|
||||
},
|
||||
no_server_name() {
|
||||
this.M_enabled = false
|
||||
this.onchange(false)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
is_demo() {
|
||||
return this.$store.getters.env.demo === true
|
||||
},
|
||||
server_name_more_than_one() {
|
||||
return this.directivesMap['server_name'] && (this.directivesMap['server_name'].length > 1 ||
|
||||
this.directivesMap['server_name'][0].params.trim().indexOf(' ') > 0)
|
||||
},
|
||||
no_server_name() {
|
||||
return !this.directivesMap['server_name']
|
||||
},
|
||||
name() {
|
||||
return this.directivesMap['server_name'][0].params.trim()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.switch-wrapper {
|
||||
position: relative;
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
import $gettext from '@/lib/translate/gettext'
|
||||
import store from '@/lib/store'
|
||||
import Vue from 'vue'
|
||||
|
||||
const issue_cert = (server_name, callback) => {
|
||||
Vue.prototype.$message.info($gettext('Getting the certificate, please wait...'), 15)
|
||||
const ws = new WebSocket(Vue.prototype.getWebSocketRoot() + '/cert/issue/' + server_name
|
||||
+ '?token=' + btoa(store.state.user.token))
|
||||
|
||||
ws.onopen = () => {
|
||||
ws.send('go')
|
||||
}
|
||||
|
||||
ws.onmessage = m => {
|
||||
const r = JSON.parse(m.data)
|
||||
switch (r.status) {
|
||||
case 'success':
|
||||
Vue.prototype.$message.success(r.message, 10)
|
||||
break
|
||||
case 'info':
|
||||
Vue.prototype.$message.info(r.message, 10)
|
||||
break
|
||||
case 'error':
|
||||
Vue.prototype.$message.error(r.message, 10)
|
||||
break
|
||||
}
|
||||
|
||||
if (r.status === 'success' && r.ssl_certificate !== undefined && r.ssl_certificate_key !== undefined) {
|
||||
callback(r.ssl_certificate, r.ssl_certificate_key)
|
||||
}
|
||||
}
|
||||
// setTimeout(() => {
|
||||
// callback('a', 'b')
|
||||
// }, 10000)
|
||||
}
|
||||
|
||||
export {issue_cert}
|
40
frontend/src/views/domain/methods.ts
Normal file
40
frontend/src/views/domain/methods.ts
Normal file
|
@ -0,0 +1,40 @@
|
|||
import gettext from '@/gettext'
|
||||
import websocket from '@/lib/websocket'
|
||||
import ReconnectingWebSocket from 'reconnecting-websocket'
|
||||
import {message} from 'ant-design-vue'
|
||||
|
||||
const {$gettext} = gettext
|
||||
|
||||
const issue_cert = async (server_name: string, callback: Function) => {
|
||||
// message.info($gettext('Getting the certificate, please wait...'), 15)
|
||||
//
|
||||
// const ws: ReconnectingWebSocket = websocket('/api/cert/issue/' + server_name)
|
||||
//
|
||||
// ws.onopen = () => {
|
||||
// ws.send('go')
|
||||
// }
|
||||
//
|
||||
// ws.onmessage = m => {
|
||||
// const r = JSON.parse(m.data)
|
||||
// switch (r.status) {
|
||||
// case 'success':
|
||||
// message.success(r.message, 10)
|
||||
// break
|
||||
// case 'info':
|
||||
// message.info(r.message, 10)
|
||||
// break
|
||||
// case 'error':
|
||||
// message.error(r.message, 10)
|
||||
// break
|
||||
// }
|
||||
//
|
||||
// if (r.status === 'success' && r.ssl_certificate !== undefined && r.ssl_certificate_key !== undefined) {
|
||||
// callback(r.ssl_certificate, r.ssl_certificate_key)
|
||||
// }
|
||||
// }
|
||||
setTimeout(() => {
|
||||
callback('a', 'b')
|
||||
}, 10000)
|
||||
}
|
||||
|
||||
export {issue_cert}
|
|
@ -28,11 +28,11 @@ function add() {
|
|||
|
||||
function save() {
|
||||
adding.value = false
|
||||
locations.push(this.location)
|
||||
locations?.push(location)
|
||||
}
|
||||
|
||||
function remove(index) {
|
||||
locations.splice(index, 1)
|
||||
function remove(index: number) {
|
||||
locations?.splice(index, 1)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -43,7 +43,7 @@ function remove(index) {
|
|||
:title="$gettext('Location')" size="small">
|
||||
<a-form layout="vertical">
|
||||
<a-form-item :label="$gettext('Comments')">
|
||||
<a-textarea v-model:value="v.comments"/>
|
||||
<a-textarea v-model:value="v.comments" :bordered="false"/>
|
||||
</a-form-item>
|
||||
<a-form-item :label="$gettext('Path')">
|
||||
<a-input addon-before="location" v-model:value="v.path"/>
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
import CertInfo from '@/views/domain/cert/CertInfo'
|
||||
// import IssueCert from '@/views/domain/cert/IssueCert'
|
||||
import DirectiveEditor from '@/views/domain/ngx_conf/directive/DirectiveEditor'
|
||||
import LocationEditor from '@/views/domain/ngx_conf/LocationEditor'
|
||||
import {computed, ref} from 'vue'
|
||||
import {useRoute} from 'vue-router'
|
||||
import {useGettext} from 'vue3-gettext'
|
||||
import Cert from '@/views/domain/cert/Cert.vue'
|
||||
|
||||
const {$gettext} = useGettext()
|
||||
|
||||
|
@ -16,15 +15,6 @@ const route = useRoute()
|
|||
const current_server_index = ref(0)
|
||||
const name = ref(route.params.name)
|
||||
|
||||
const init_ssl_status = ref(false)
|
||||
|
||||
function update_cert_info() {
|
||||
// TODO
|
||||
// if (name.value && this.$refs['cert-info' + this.current_server_index]) {
|
||||
// this.$refs['cert-info' + this.current_server_index].get()
|
||||
// }
|
||||
}
|
||||
|
||||
function change_tls(r: any) {
|
||||
if (r) {
|
||||
// deep copy servers[0] to servers[1]
|
||||
|
@ -140,17 +130,16 @@ const current_support_ssl = computed(() => {
|
|||
|
||||
<div class="tab-content">
|
||||
<template v-if="current_support_ssl&&enabled">
|
||||
<cert-info :domain="name" v-if="current_support_ssl"/>
|
||||
<!-- <issue-cert-->
|
||||
<!-- :current_server_directives="current_server_directives"-->
|
||||
<!-- :directives-map="directivesMap"-->
|
||||
<!-- v-model="auto_cert"-->
|
||||
<!-- />-->
|
||||
<cert
|
||||
v-if="current_support_ssl"
|
||||
:current_server_directives="current_server_directives"
|
||||
:directives-map="directivesMap"
|
||||
v-model:enabled="auto_cert"/>
|
||||
</template>
|
||||
|
||||
<template v-if="v.comments">
|
||||
<h3 v-translate>Comments</h3>
|
||||
<p style="white-space: pre-wrap;">{{ v.comments }}</p>
|
||||
<a-textarea v-model:value="v.comments" :bordered="false"/>
|
||||
</template>
|
||||
|
||||
<directive-editor :ngx_directives="v.directives"/>
|
||||
|
|
|
@ -3,7 +3,7 @@ import {If} from '@/views/domain/ngx_conf'
|
|||
import CodeEditor from '@/components/CodeEditor'
|
||||
import {reactive, ref} from 'vue'
|
||||
import {useGettext} from 'vue3-gettext'
|
||||
import {CloseOutlined} from '@ant-design/icons-vue'
|
||||
import {DeleteOutlined} from '@ant-design/icons-vue'
|
||||
|
||||
const {$gettext} = useGettext()
|
||||
|
||||
|
@ -52,17 +52,18 @@ function save() {
|
|||
</a-form-item>
|
||||
<a-form-item>
|
||||
<code-editor v-if="mode===If" default-height="100px" v-model:content="directive.params"/>
|
||||
|
||||
<a-input-group compact v-else>
|
||||
|
||||
<div class="input-wrapper" v-else>
|
||||
<a-input-group compact>
|
||||
<a-input style="width: 30%" :placeholder="$gettext('Directive')" v-model="directive.directive"/>
|
||||
|
||||
<a-input style="width: 70%" :placeholder="$gettext('Params')" v-model="directive.params">
|
||||
<template #suffix>
|
||||
<CloseOutlined @click="adding=false" style="color: rgba(0,0,0,.45);font-size: 10px;"/>
|
||||
</template>
|
||||
</a-input>
|
||||
<a-input style="width: 70%" :placeholder="$gettext('Params')" v-model="directive.params"/>
|
||||
</a-input-group>
|
||||
<a-button @click="adding=false">
|
||||
<template #icon>
|
||||
<DeleteOutlined style="font-size: 14px;"/>
|
||||
</template>
|
||||
</a-button>
|
||||
|
||||
</div>
|
||||
</a-form-item>
|
||||
</div>
|
||||
<a-button block v-if="!adding" @click="add">{{ $gettext('Add Directive Below') }}</a-button>
|
||||
|
@ -73,5 +74,8 @@ function save() {
|
|||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
||||
.input-wrapper {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -4,7 +4,7 @@ import {If} from '@/views/domain/ngx_conf'
|
|||
import DirectiveAdd from '@/views/domain/ngx_conf/directive/DirectiveAdd'
|
||||
import {useGettext} from 'vue3-gettext'
|
||||
import {reactive, ref} from 'vue'
|
||||
import {CloseOutlined} from '@ant-design/icons-vue'
|
||||
import {DeleteOutlined} from '@ant-design/icons-vue'
|
||||
|
||||
const {$gettext} = useGettext()
|
||||
|
||||
|
@ -45,19 +45,23 @@ function onSave(idx: number) {
|
|||
<a-form-item v-for="(directive,index) in ngx_directives" @click="current_idx=index">
|
||||
<code-editor v-if="directive.directive === If" v-model:content="directive.params"
|
||||
defaultHeight="100px"/>
|
||||
<div class="input-wrapper" v-else>
|
||||
<a-input :addon-before="directive.directive" v-model:value="directive.params" @click="current_idx=k"
|
||||
v-else>
|
||||
<template #suffix>
|
||||
>
|
||||
</a-input>
|
||||
<a-popconfirm @confirm="remove(index)"
|
||||
:title="$gettext('Are you sure you want to remove this directive?')"
|
||||
:ok-text="$gettext('Yes')"
|
||||
:cancel-text="$gettext('No')">
|
||||
<CloseOutlined style="color: rgba(0,0,0,.45);font-size: 10px;"/>
|
||||
</a-popconfirm>
|
||||
<a-button>
|
||||
<template #icon>
|
||||
<DeleteOutlined style="font-size: 14px;"/>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-button>
|
||||
</a-popconfirm>
|
||||
</div>
|
||||
<transition name="slide">
|
||||
<div v-if="current_idx===index" class="extra">
|
||||
<div v-if="current_idx===index" class="directive-editor-extra">
|
||||
<div class="extra-content">
|
||||
<a-form layout="vertical">
|
||||
<a-form-item :label="$gettext('Comments')">
|
||||
|
@ -74,7 +78,7 @@ function onSave(idx: number) {
|
|||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.extra {
|
||||
.directive-editor-extra {
|
||||
background-color: #fafafa;
|
||||
padding: 10px 20px 20px;
|
||||
margin-bottom: 10px;
|
||||
|
@ -91,4 +95,9 @@ function onSave(idx: number) {
|
|||
.slide-enter-to, .slide-leave-from {
|
||||
max-height: 600px;
|
||||
}
|
||||
|
||||
.input-wrapper {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -45,7 +45,7 @@ const columns = [{
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<std-curd :columns="columns" :api="user"/>
|
||||
<std-curd :title="$gettext('Manage Users')" :columns="columns" :api="user"/>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"version":"1.5.0","build_id":11,"total_build":81}
|
||||
{"version":"1.5.0","build_id":14,"total_build":84}
|
|
@ -58,6 +58,9 @@ export default defineConfig({
|
|||
css: {
|
||||
preprocessorOptions: {
|
||||
less: {
|
||||
modifyVars: {
|
||||
'border-radius-base': '4px',
|
||||
},
|
||||
javascriptEnabled: true,
|
||||
}
|
||||
},
|
||||
|
|
|
@ -11,18 +11,9 @@ import (
|
|||
)
|
||||
|
||||
func GetUsers(c *gin.Context) {
|
||||
curd := model.NewCurd(&model.Auth{})
|
||||
data := model.GetUserList(c, c.Query("name"))
|
||||
|
||||
var list []model.Auth
|
||||
err := curd.GetList(&list)
|
||||
|
||||
if err != nil {
|
||||
ErrHandler(c, err)
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"data": list,
|
||||
})
|
||||
c.JSON(http.StatusOK, data)
|
||||
}
|
||||
|
||||
func GetUser(c *gin.Context) {
|
||||
|
|
|
@ -2,6 +2,7 @@ package model
|
|||
|
||||
import (
|
||||
"github.com/0xJacky/Nginx-UI/server/settings"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/golang-jwt/jwt"
|
||||
"time"
|
||||
)
|
||||
|
@ -30,6 +31,23 @@ func GetUser(name string) (user Auth, err error) {
|
|||
return user, err
|
||||
}
|
||||
|
||||
func GetUserList(c *gin.Context, username interface{}) (data DataList) {
|
||||
var total int64
|
||||
db.Model(&Auth{}).Count(&total)
|
||||
var users []Auth
|
||||
|
||||
result := db.Model(&Auth{}).Scopes(orderAndPaginate(c))
|
||||
|
||||
if username != "" {
|
||||
result = result.Where("name LIKE ?", "%"+username.(string)+"%")
|
||||
}
|
||||
|
||||
result.Find(&users)
|
||||
|
||||
data = GetListWithPagination(&users, c, total)
|
||||
return
|
||||
}
|
||||
|
||||
func DeleteToken(token string) error {
|
||||
return db.Where("token = ?", token).Delete(&AuthToken{}).Error
|
||||
}
|
||||
|
|
116
server/model/model.go
Normal file
116
server/model/model.go
Normal file
|
@ -0,0 +1,116 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/0xJacky/Nginx-UI/server/settings"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/spf13/cast"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
"log"
|
||||
"path"
|
||||
"time"
|
||||
)
|
||||
|
||||
var db *gorm.DB
|
||||
|
||||
type Model struct {
|
||||
ID uint `gorm:"primary_key" json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt *time.Time `gorm:"index" json:"deleted_at"`
|
||||
}
|
||||
|
||||
func Init() {
|
||||
dbPath := path.Join(path.Dir(settings.ConfPath), fmt.Sprintf("%s.db", settings.ServerSettings.Database))
|
||||
var err error
|
||||
db, err = gorm.Open(sqlite.Open(dbPath), &gorm.Config{
|
||||
Logger: logger.Default.LogMode(logger.Info),
|
||||
PrepareStmt: true,
|
||||
})
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
// Migrate the schema
|
||||
AutoMigrate(&ConfigBackup{})
|
||||
AutoMigrate(&Auth{})
|
||||
AutoMigrate(&AuthToken{})
|
||||
AutoMigrate(&Cert{})
|
||||
}
|
||||
|
||||
func AutoMigrate(model interface{}) {
|
||||
err := db.AutoMigrate(model)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func orderAndPaginate(c *gin.Context) func(db *gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
sort := c.DefaultQuery("sort", "desc")
|
||||
order := c.DefaultQuery("order_by", "id") +
|
||||
" " + sort
|
||||
|
||||
page := cast.ToInt(c.Query("page"))
|
||||
if page == 0 {
|
||||
page = 1
|
||||
}
|
||||
pageSize := settings.ServerSettings.PageSize
|
||||
reqPageSize := c.Query("page_size")
|
||||
if reqPageSize != "" {
|
||||
pageSize = cast.ToInt(reqPageSize)
|
||||
}
|
||||
offset := (page - 1) * pageSize
|
||||
|
||||
return db.Order(order).Offset(offset).Limit(pageSize)
|
||||
}
|
||||
}
|
||||
|
||||
func totalPage(total int64, pageSize int) int64 {
|
||||
n := total / int64(pageSize)
|
||||
if total%int64(pageSize) > 0 {
|
||||
n++
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
type Pagination struct {
|
||||
Total int64 `json:"total"`
|
||||
PerPage int `json:"per_page"`
|
||||
CurrentPage int `json:"current_page"`
|
||||
TotalPages int64 `json:"total_pages"`
|
||||
}
|
||||
|
||||
type DataList struct {
|
||||
Data interface{} `json:"data"`
|
||||
Pagination Pagination `json:"pagination,omitempty"`
|
||||
}
|
||||
|
||||
func GetListWithPagination(models interface{},
|
||||
c *gin.Context, totalRecords int64) (result DataList) {
|
||||
|
||||
page := cast.ToInt(c.Query("page"))
|
||||
if page == 0 {
|
||||
page = 1
|
||||
}
|
||||
|
||||
result = DataList{}
|
||||
|
||||
result.Data = models
|
||||
|
||||
pageSize := settings.ServerSettings.PageSize
|
||||
reqPageSize := c.Query("page_size")
|
||||
if reqPageSize != "" {
|
||||
pageSize = cast.ToInt(reqPageSize)
|
||||
}
|
||||
|
||||
result.Pagination = Pagination{
|
||||
Total: totalRecords,
|
||||
PerPage: pageSize,
|
||||
CurrentPage: page,
|
||||
TotalPages: totalPage(totalRecords, pageSize),
|
||||
}
|
||||
|
||||
return
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/0xJacky/Nginx-UI/server/settings"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
"log"
|
||||
"path"
|
||||
"time"
|
||||
)
|
||||
|
||||
var db *gorm.DB
|
||||
|
||||
type Model struct {
|
||||
ID uint `gorm:"primary_key" json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt *time.Time `gorm:"index" json:"deleted_at"`
|
||||
}
|
||||
|
||||
func Init() {
|
||||
dbPath := path.Join(path.Dir(settings.ConfPath), fmt.Sprintf("%s.db", settings.ServerSettings.Database))
|
||||
var err error
|
||||
db, err = gorm.Open(sqlite.Open(dbPath), &gorm.Config{
|
||||
Logger: logger.Default.LogMode(logger.Info),
|
||||
PrepareStmt: true,
|
||||
})
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
// Migrate the schema
|
||||
AutoMigrate(&ConfigBackup{})
|
||||
AutoMigrate(&Auth{})
|
||||
AutoMigrate(&AuthToken{})
|
||||
AutoMigrate(&Cert{})
|
||||
}
|
||||
|
||||
func AutoMigrate(model interface{}) {
|
||||
err := db.AutoMigrate(model)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
|
@ -25,6 +25,7 @@ type Server struct {
|
|||
Database string
|
||||
StartCmd string
|
||||
Demo bool
|
||||
PageSize int
|
||||
}
|
||||
|
||||
var ServerSettings = &Server{
|
||||
|
@ -34,6 +35,7 @@ var ServerSettings = &Server{
|
|||
Database: "database",
|
||||
StartCmd: "login",
|
||||
Demo: false,
|
||||
PageSize: 10,
|
||||
}
|
||||
|
||||
var ConfPath string
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue