mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2025-05-10 18:05:48 +02:00
feat(china): set icp number and public security number #780
This commit is contained in:
parent
2950be6e82
commit
e326f5e930
13 changed files with 150 additions and 28 deletions
14
api/public/layout.go
Normal file
14
api/public/layout.go
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
package public
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/0xJacky/Nginx-UI/settings"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetICPSettings(c *gin.Context) {
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"icp_number": settings.NodeSettings.ICPNumber,
|
||||||
|
"public_security_number": settings.NodeSettings.PublicSecurityNumber,
|
||||||
|
})
|
||||||
|
}
|
7
api/public/router.go
Normal file
7
api/public/router.go
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package public
|
||||||
|
|
||||||
|
import "github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
func InitRouter(r *gin.RouterGroup) {
|
||||||
|
r.GET("/icp_settings", GetICPSettings)
|
||||||
|
}
|
1
app/components.d.ts
vendored
1
app/components.d.ts
vendored
|
@ -76,6 +76,7 @@ declare module 'vue' {
|
||||||
CodeEditorCodeEditor: typeof import('./src/components/CodeEditor/CodeEditor.vue')['default']
|
CodeEditorCodeEditor: typeof import('./src/components/CodeEditor/CodeEditor.vue')['default']
|
||||||
EnvIndicatorEnvIndicator: typeof import('./src/components/EnvIndicator/EnvIndicator.vue')['default']
|
EnvIndicatorEnvIndicator: typeof import('./src/components/EnvIndicator/EnvIndicator.vue')['default']
|
||||||
FooterToolbarFooterToolBar: typeof import('./src/components/FooterToolbar/FooterToolBar.vue')['default']
|
FooterToolbarFooterToolBar: typeof import('./src/components/FooterToolbar/FooterToolBar.vue')['default']
|
||||||
|
ICPICP: typeof import('./src/components/ICP/ICP.vue')['default']
|
||||||
LogoLogo: typeof import('./src/components/Logo/Logo.vue')['default']
|
LogoLogo: typeof import('./src/components/Logo/Logo.vue')['default']
|
||||||
NginxControlNginxControl: typeof import('./src/components/NginxControl/NginxControl.vue')['default']
|
NginxControlNginxControl: typeof import('./src/components/NginxControl/NginxControl.vue')['default']
|
||||||
NodeSelectorNodeSelector: typeof import('./src/components/NodeSelector/NodeSelector.vue')['default']
|
NodeSelectorNodeSelector: typeof import('./src/components/NodeSelector/NodeSelector.vue')['default']
|
||||||
|
|
14
app/src/api/public.ts
Normal file
14
app/src/api/public.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import http from '@/lib/http'
|
||||||
|
|
||||||
|
export interface ICP {
|
||||||
|
icp_number: string
|
||||||
|
public_security_number: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const publicApi = {
|
||||||
|
getICP<ICP>() {
|
||||||
|
return http.get('/icp_settings')
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default publicApi
|
|
@ -63,6 +63,8 @@ export interface NginxSettings {
|
||||||
export interface NodeSettings {
|
export interface NodeSettings {
|
||||||
name: string
|
name: string
|
||||||
secret: string
|
secret: string
|
||||||
|
icp_number: string
|
||||||
|
public_security_number: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OpenaiSettings {
|
export interface OpenaiSettings {
|
||||||
|
|
50
app/src/components/ICP/ICP.vue
Normal file
50
app/src/components/ICP/ICP.vue
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { ICP } from '@/api/public'
|
||||||
|
import publicApi from '@/api/public'
|
||||||
|
|
||||||
|
const icp = ref<ICP>({
|
||||||
|
icp_number: '',
|
||||||
|
public_security_number: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
publicApi.getICP().then(r => {
|
||||||
|
icp.value = r
|
||||||
|
})
|
||||||
|
|
||||||
|
const enabled = computed(() => {
|
||||||
|
return icp.value.icp_number || icp.value.public_security_number
|
||||||
|
})
|
||||||
|
|
||||||
|
const showDot = computed(() => icp.value.icp_number && icp.value.public_security_number)
|
||||||
|
|
||||||
|
const publicSecurityNumberLink = computed(() =>
|
||||||
|
`https://www.beian.gov.cn/portal/registerSystemInfo?recordcode=${icp.value.public_security_number}`)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div v-if="enabled">
|
||||||
|
<a href="https://beian.miit.gov.cn/" target="_blank">{{ icp.icp_number }}</a>
|
||||||
|
<span v-if="showDot"> · </span>
|
||||||
|
<a v-if="icp.public_security_number" class="public_security_number" :href="publicSecurityNumberLink">
|
||||||
|
<img src="//www.beian.gov.cn/img/new/gongan.png" alt="公安备案">
|
||||||
|
<span class="ml-5">{{ icp.public_security_number }}</span></a>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
a {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.public_security_number {
|
||||||
|
position: relative;
|
||||||
|
img {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -2,6 +2,7 @@
|
||||||
import auth from '@/api/auth'
|
import auth from '@/api/auth'
|
||||||
import install from '@/api/install'
|
import install from '@/api/install'
|
||||||
import passkey from '@/api/passkey'
|
import passkey from '@/api/passkey'
|
||||||
|
import ICP from '@/components/ICP/ICP.vue'
|
||||||
import SetLanguage from '@/components/SetLanguage/SetLanguage.vue'
|
import SetLanguage from '@/components/SetLanguage/SetLanguage.vue'
|
||||||
import SwitchAppearance from '@/components/SwitchAppearance/SwitchAppearance.vue'
|
import SwitchAppearance from '@/components/SwitchAppearance/SwitchAppearance.vue'
|
||||||
import Authorization from '@/components/TwoFA/Authorization.vue'
|
import Authorization from '@/components/TwoFA/Authorization.vue'
|
||||||
|
@ -23,7 +24,7 @@ install.get_lock().then(async (r: { lock: boolean }) => {
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const enabled2FA = ref(false)
|
const enabled2FA = ref(false)
|
||||||
const refOTP = ref()
|
const refOTP = useTemplateRef('refOTP')
|
||||||
const passcode = ref('')
|
const passcode = ref('')
|
||||||
const recoveryCode = ref('')
|
const recoveryCode = ref('')
|
||||||
const passkeyConfigStatus = ref(false)
|
const passkeyConfigStatus = ref(false)
|
||||||
|
@ -266,7 +267,10 @@ async function handlePasskeyLogin() {
|
||||||
</AFormItem>
|
</AFormItem>
|
||||||
</AForm>
|
</AForm>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<p>Copyright © 2021 - {{ thisYear }} Nginx UI</p>
|
<p class="mb-4">
|
||||||
|
Copyright © 2021 - {{ thisYear }} Nginx UI
|
||||||
|
</p>
|
||||||
|
<ICP class="mb-4" />
|
||||||
Language
|
Language
|
||||||
<SetLanguage class="inline" />
|
<SetLanguage class="inline" />
|
||||||
<div class="flex justify-center mt-4">
|
<div class="flex justify-center mt-4">
|
||||||
|
@ -295,7 +299,7 @@ async function handlePasskeyLogin() {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
|
||||||
.login-form {
|
.login-form {
|
||||||
max-width: 400px;
|
max-width: 420px;
|
||||||
width: 80%;
|
width: 80%;
|
||||||
|
|
||||||
.project-title {
|
.project-title {
|
||||||
|
@ -313,7 +317,7 @@ async function handlePasskeyLogin() {
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
padding: 30px;
|
padding: 30px 20px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,15 @@ const errors: Record<string, Record<string, string>> = inject('errors') as Recor
|
||||||
<AFormItem :label="$gettext('Terminal Start Command')">
|
<AFormItem :label="$gettext('Terminal Start Command')">
|
||||||
<p>{{ data.terminal.start_cmd }}</p>
|
<p>{{ data.terminal.start_cmd }}</p>
|
||||||
</AFormItem>
|
</AFormItem>
|
||||||
|
<AFormItem
|
||||||
|
:label="$gettext('Node name')"
|
||||||
|
:validate-status="errors?.node?.name ? 'error' : ''"
|
||||||
|
:help="errors?.node?.name.includes('safety_text')
|
||||||
|
? $gettext('The node name should only contain letters, unicode, numbers, hyphens, dashes, and dots.')
|
||||||
|
: $gettext('Customize the name of local node to be displayed in the environment indicator.')"
|
||||||
|
>
|
||||||
|
<AInput v-model:value="data.node.name" />
|
||||||
|
</AFormItem>
|
||||||
<AFormItem
|
<AFormItem
|
||||||
:label="$gettext('Github Proxy')"
|
:label="$gettext('Github Proxy')"
|
||||||
:validate-status="errors?.http?.github_proxy ? 'error' : ''"
|
:validate-status="errors?.http?.github_proxy ? 'error' : ''"
|
||||||
|
@ -39,13 +48,28 @@ const errors: Record<string, Record<string, string>> = inject('errors') as Recor
|
||||||
/>
|
/>
|
||||||
</AFormItem>
|
</AFormItem>
|
||||||
<AFormItem
|
<AFormItem
|
||||||
:label="$gettext('Node name')"
|
:label="$gettext('ICP Number')"
|
||||||
:validate-status="errors?.node?.name ? 'error' : ''"
|
:validate-status="errors?.node?.icp_number ? 'error' : ''"
|
||||||
:help="errors?.node?.name.includes('safety_text')
|
:help="errors?.node?.icp_number.includes('safety_text')
|
||||||
? $gettext('The node name should only contain letters, unicode, numbers, hyphens, dashes, and dots.')
|
? $gettext('The ICP Number should only contain letters, unicode, numbers, hyphens, dashes, and dots.')
|
||||||
: $gettext('Customize the name of local node to be displayed in the environment indicator.')"
|
: ''"
|
||||||
>
|
>
|
||||||
<AInput v-model:value="data.node.name" />
|
<AInput
|
||||||
|
v-model:value="data.node.icp_number"
|
||||||
|
:placeholder="$gettext('For Chinese user')"
|
||||||
|
/>
|
||||||
|
</AFormItem>
|
||||||
|
<AFormItem
|
||||||
|
:label="$gettext('Public Security Number')"
|
||||||
|
:validate-status="errors?.node?.public_security_number ? 'error' : ''"
|
||||||
|
:help="errors?.node?.public_security_number.includes('safety_text')
|
||||||
|
? $gettext('The Public Security Number should only contain letters, unicode, numbers, hyphens, dashes, and dots.')
|
||||||
|
: ''"
|
||||||
|
>
|
||||||
|
<AInput
|
||||||
|
v-model:value="data.node.public_security_number"
|
||||||
|
:placeholder="$gettext('For Chinese user')"
|
||||||
|
/>
|
||||||
</AFormItem>
|
</AFormItem>
|
||||||
</AForm>
|
</AForm>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -23,3 +23,16 @@
|
||||||
|
|
||||||
默认情况下,如果您启用了跳过安装模式,而没有在服务器部分设置 `App.JwtSecret` 和 `Node.Secret` 选项,
|
默认情况下,如果您启用了跳过安装模式,而没有在服务器部分设置 `App.JwtSecret` 和 `Node.Secret` 选项,
|
||||||
Nginx UI 将为这两个选项生成一个随机的 UUID 值。
|
Nginx UI 将为这两个选项生成一个随机的 UUID 值。
|
||||||
|
|
||||||
|
## ICPNumber
|
||||||
|
- 类型: `string`
|
||||||
|
- 版本: `>= v2.0.0-beta.42`
|
||||||
|
|
||||||
|
此选项用于设置 ICP 备案号。
|
||||||
|
|
||||||
|
## PublicSecurityNumber
|
||||||
|
- 类型: `string`
|
||||||
|
- 版本: `>= v2.0.0-beta.42`
|
||||||
|
|
||||||
|
此选项用于设置 ICP 备案号。
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/0xJacky/Nginx-UI/api/nginx"
|
"github.com/0xJacky/Nginx-UI/api/nginx"
|
||||||
"github.com/0xJacky/Nginx-UI/api/notification"
|
"github.com/0xJacky/Nginx-UI/api/notification"
|
||||||
"github.com/0xJacky/Nginx-UI/api/openai"
|
"github.com/0xJacky/Nginx-UI/api/openai"
|
||||||
|
"github.com/0xJacky/Nginx-UI/api/public"
|
||||||
"github.com/0xJacky/Nginx-UI/api/settings"
|
"github.com/0xJacky/Nginx-UI/api/settings"
|
||||||
"github.com/0xJacky/Nginx-UI/api/sites"
|
"github.com/0xJacky/Nginx-UI/api/sites"
|
||||||
"github.com/0xJacky/Nginx-UI/api/streams"
|
"github.com/0xJacky/Nginx-UI/api/streams"
|
||||||
|
@ -39,6 +40,7 @@ func InitRouter() {
|
||||||
|
|
||||||
root := r.Group("/api")
|
root := r.Group("/api")
|
||||||
{
|
{
|
||||||
|
public.InitRouter(root)
|
||||||
system.InitPublicRouter(root)
|
system.InitPublicRouter(root)
|
||||||
user.InitAuthRouter(root)
|
user.InitAuthRouter(root)
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,4 @@ type HTTP struct {
|
||||||
InsecureSkipVerify bool `json:"insecure_skip_verify" protected:"true"`
|
InsecureSkipVerify bool `json:"insecure_skip_verify" protected:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var HTTPSettings = &HTTP{
|
var HTTPSettings = &HTTP{}
|
||||||
GithubProxy: "",
|
|
||||||
InsecureSkipVerify: false,
|
|
||||||
}
|
|
||||||
|
|
|
@ -11,7 +11,4 @@ type Nginx struct {
|
||||||
RestartCmd string `json:"restart_cmd" protected:"true"`
|
RestartCmd string `json:"restart_cmd" protected:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var NginxSettings = &Nginx{
|
var NginxSettings = &Nginx{}
|
||||||
AccessLogPath: "",
|
|
||||||
ErrorLogPath: "",
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
package settings
|
package settings
|
||||||
|
|
||||||
type Node struct {
|
type Node struct {
|
||||||
Name string `json:"name" binding:"omitempty,safety_text"`
|
Name string `json:"name" binding:"omitempty,safety_text"`
|
||||||
Secret string `json:"secret" protected:"true"`
|
Secret string `json:"secret" protected:"true"`
|
||||||
SkipInstallation bool `json:"skip_installation" protected:"true"`
|
SkipInstallation bool `json:"skip_installation" protected:"true"`
|
||||||
Demo bool `json:"demo" protected:"true"`
|
Demo bool `json:"demo" protected:"true"`
|
||||||
|
ICPNumber string `json:"icp_number" binding:"omitempty,safety_text"`
|
||||||
|
PublicSecurityNumber string `json:"public_security_number" binding:"omitempty,safety_text"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var NodeSettings = &Node{
|
var NodeSettings = &Node{}
|
||||||
Name: "",
|
|
||||||
Secret: "",
|
|
||||||
SkipInstallation: false,
|
|
||||||
Demo: false,
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue