mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2025-05-11 10:25:52 +02:00
232 lines
6.1 KiB
Vue
232 lines
6.1 KiB
Vue
<script setup lang="ts">
|
|
import { message } from 'ant-design-vue'
|
|
import type { Ref } from 'vue'
|
|
import { formatDateTime } from '@/lib/helper'
|
|
import FooterToolBar from '@/components/FooterToolbar/FooterToolBar.vue'
|
|
import config from '@/api/config'
|
|
import CodeEditor from '@/components/CodeEditor/CodeEditor.vue'
|
|
import ngx from '@/api/ngx'
|
|
import InspectConfig from '@/views/config/InspectConfig.vue'
|
|
import ChatGPT from '@/components/ChatGPT/ChatGPT.vue'
|
|
import type { ChatComplicationMessage } from '@/api/openai'
|
|
|
|
const route = useRoute()
|
|
const router = useRouter()
|
|
const refForm = ref()
|
|
const refInspectConfig = ref()
|
|
const origName = ref('')
|
|
const addMode = computed(() => !route.params.name)
|
|
const errors = ref({})
|
|
|
|
const basePath = computed(() => {
|
|
if (route.query.basePath)
|
|
return route?.query?.basePath?.toString().replaceAll('/', '')
|
|
else if (typeof route.params.name === 'object')
|
|
return (route.params.name as string[]).slice(0, -1).join('/')
|
|
else
|
|
return ''
|
|
})
|
|
|
|
const data = ref({
|
|
name: '',
|
|
content: '',
|
|
filepath: '',
|
|
})
|
|
|
|
const historyChatgptRecord = ref([]) as Ref<ChatComplicationMessage[]>
|
|
const activeKey = ref(['basic', 'chatgpt'])
|
|
const modifiedAt = ref('')
|
|
const nginxConfigBase = ref('')
|
|
|
|
const newPath = computed(() => [nginxConfigBase.value, basePath.value, data.value.name]
|
|
.filter(v => v)
|
|
.join('/'))
|
|
|
|
const relativePath = computed(() => (route.params.name as string[]).join('/'))
|
|
|
|
async function init() {
|
|
const { name } = route.params
|
|
|
|
data.value.name = name?.[name?.length - 1] ?? ''
|
|
origName.value = data.value.name
|
|
if (data.value.name) {
|
|
config.get(relativePath.value).then(r => {
|
|
data.value = r
|
|
historyChatgptRecord.value = r.chatgpt_messages
|
|
modifiedAt.value = r.modified_at
|
|
}).catch(r => {
|
|
message.error(r.message ?? $gettext('Server error'))
|
|
})
|
|
}
|
|
else {
|
|
data.value.content = ''
|
|
historyChatgptRecord.value = []
|
|
data.value.filepath = ''
|
|
}
|
|
}
|
|
|
|
onMounted(async () => {
|
|
await config.get_base_path().then(r => {
|
|
nginxConfigBase.value = r.base_path
|
|
})
|
|
await init()
|
|
})
|
|
|
|
function save() {
|
|
refForm.value.validate().then(() => {
|
|
config.save(addMode.value ? null : relativePath.value, {
|
|
name: data.value.name,
|
|
filepath: data.value.filepath,
|
|
new_filepath: newPath.value,
|
|
content: data.value.content,
|
|
}).then(r => {
|
|
data.value.content = r.content
|
|
message.success($gettext('Saved successfully'))
|
|
router.push(`/config/${r.filepath.replaceAll(`${nginxConfigBase.value}/`, '')}/edit`)
|
|
}).catch(e => {
|
|
errors.value = e.errors
|
|
message.error($gettext('Save error %{msg}', { msg: e.message ?? '' }))
|
|
}).finally(() => {
|
|
refInspectConfig.value.test()
|
|
})
|
|
})
|
|
}
|
|
|
|
function formatCode() {
|
|
ngx.format_code(data.value.content).then(r => {
|
|
data.value.content = r.content
|
|
message.success($gettext('Format successfully'))
|
|
}).catch(r => {
|
|
message.error($gettext('Format error %{msg}', { msg: r.message ?? '' }))
|
|
})
|
|
}
|
|
|
|
function goBack() {
|
|
router.push({
|
|
path: '/config',
|
|
query: {
|
|
dir: basePath.value || undefined,
|
|
},
|
|
})
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<ARow :gutter="16">
|
|
<ACol
|
|
:xs="24"
|
|
:sm="24"
|
|
:md="18"
|
|
>
|
|
<ACard :title="addMode ? $gettext('Add Configuration') : $gettext('Edit Configuration')">
|
|
<InspectConfig
|
|
v-show="!addMode"
|
|
ref="refInspectConfig"
|
|
/>
|
|
<CodeEditor v-model:content="data.content" />
|
|
<FooterToolBar>
|
|
<ASpace>
|
|
<AButton @click="goBack">
|
|
{{ $gettext('Back') }}
|
|
</AButton>
|
|
<AButton @click="formatCode">
|
|
{{ $gettext('Format Code') }}
|
|
</AButton>
|
|
<AButton
|
|
type="primary"
|
|
@click="save"
|
|
>
|
|
{{ $gettext('Save') }}
|
|
</AButton>
|
|
</ASpace>
|
|
</FooterToolBar>
|
|
</ACard>
|
|
</ACol>
|
|
|
|
<ACol
|
|
:xs="24"
|
|
:sm="24"
|
|
:md="6"
|
|
>
|
|
<ACard class="col-right">
|
|
<ACollapse
|
|
v-model:activeKey="activeKey"
|
|
ghost
|
|
>
|
|
<ACollapsePanel
|
|
key="basic"
|
|
:header="$gettext('Basic')"
|
|
>
|
|
<AForm
|
|
ref="refForm"
|
|
layout="vertical"
|
|
:model="data"
|
|
:rules="{
|
|
name: [
|
|
{ required: true, message: $gettext('Please input a filename') },
|
|
{ pattern: /^[^\\/]+$/, message: $gettext('Invalid filename') },
|
|
],
|
|
}"
|
|
>
|
|
<AFormItem
|
|
name="name"
|
|
:label="$gettext('Name')"
|
|
>
|
|
<AInput v-model:value="data.name" />
|
|
</AFormItem>
|
|
<AFormItem
|
|
v-if="!addMode"
|
|
:label="$gettext('Path')"
|
|
>
|
|
{{ data.filepath }}
|
|
</AFormItem>
|
|
<AFormItem
|
|
v-show="data.name !== origName"
|
|
:label="addMode ? $gettext('New Path') : $gettext('Changed Path')"
|
|
required
|
|
>
|
|
{{ newPath }}
|
|
</AFormItem>
|
|
<AFormItem
|
|
v-if="!addMode"
|
|
:label="$gettext('Updated at')"
|
|
>
|
|
{{ formatDateTime(modifiedAt) }}
|
|
</AFormItem>
|
|
</AForm>
|
|
</ACollapsePanel>
|
|
<ACollapsePanel
|
|
key="chatgpt"
|
|
header="ChatGPT"
|
|
>
|
|
<ChatGPT
|
|
v-model:history-messages="historyChatgptRecord"
|
|
:content="data.content"
|
|
:path="data.filepath"
|
|
/>
|
|
</ACollapsePanel>
|
|
</ACollapse>
|
|
</ACard>
|
|
</ACol>
|
|
</ARow>
|
|
</template>
|
|
|
|
<style lang="less" scoped>
|
|
.col-right {
|
|
position: sticky;
|
|
top: 78px;
|
|
|
|
:deep(.ant-card-body) {
|
|
max-height: 100vh;
|
|
overflow-y: scroll;
|
|
}
|
|
}
|
|
|
|
:deep(.ant-collapse-ghost > .ant-collapse-item > .ant-collapse-content > .ant-collapse-content-box) {
|
|
padding: 0;
|
|
}
|
|
|
|
:deep(.ant-collapse > .ant-collapse-item > .ant-collapse-header) {
|
|
padding: 0 0 10px 0;
|
|
}
|
|
</style>
|