Procházet zdrojové kódy

feat(china): set icp number and public security number #780

Jacky před 4 měsíci
rodič
revize
e326f5e930

+ 14 - 0
api/public/layout.go

@@ -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 - 0
api/public/router.go

@@ -0,0 +1,7 @@
+package public
+
+import "github.com/gin-gonic/gin"
+
+func InitRouter(r *gin.RouterGroup) {
+	r.GET("/icp_settings", GetICPSettings)
+}

+ 1 - 0
app/components.d.ts

@@ -76,6 +76,7 @@ declare module 'vue' {
     CodeEditorCodeEditor: typeof import('./src/components/CodeEditor/CodeEditor.vue')['default']
     EnvIndicatorEnvIndicator: typeof import('./src/components/EnvIndicator/EnvIndicator.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']
     NginxControlNginxControl: typeof import('./src/components/NginxControl/NginxControl.vue')['default']
     NodeSelectorNodeSelector: typeof import('./src/components/NodeSelector/NodeSelector.vue')['default']

+ 14 - 0
app/src/api/public.ts

@@ -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

+ 2 - 0
app/src/api/settings.ts

@@ -63,6 +63,8 @@ export interface NginxSettings {
 export interface NodeSettings {
   name: string
   secret: string
+  icp_number: string
+  public_security_number: number
 }
 
 export interface OpenaiSettings {

+ 50 - 0
app/src/components/ICP/ICP.vue

@@ -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>

+ 8 - 4
app/src/views/other/Login.vue

@@ -2,6 +2,7 @@
 import auth from '@/api/auth'
 import install from '@/api/install'
 import passkey from '@/api/passkey'
+import ICP from '@/components/ICP/ICP.vue'
 import SetLanguage from '@/components/SetLanguage/SetLanguage.vue'
 import SwitchAppearance from '@/components/SwitchAppearance/SwitchAppearance.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 enabled2FA = ref(false)
-const refOTP = ref()
+const refOTP = useTemplateRef('refOTP')
 const passcode = ref('')
 const recoveryCode = ref('')
 const passkeyConfigStatus = ref(false)
@@ -266,7 +267,10 @@ async function handlePasskeyLogin() {
             </AFormItem>
           </AForm>
           <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
             <SetLanguage class="inline" />
             <div class="flex justify-center mt-4">
@@ -295,7 +299,7 @@ async function handlePasskeyLogin() {
   height: 100vh;
 
   .login-form {
-    max-width: 400px;
+    max-width: 420px;
     width: 80%;
 
     .project-title {
@@ -313,7 +317,7 @@ async function handlePasskeyLogin() {
     }
 
     .footer {
-      padding: 30px;
+      padding: 30px 20px;
       text-align: center;
       font-size: 14px;
     }

+ 30 - 6
app/src/views/preference/BasicSettings.vue

@@ -26,6 +26,15 @@ const errors: Record<string, Record<string, string>> = inject('errors') as Recor
     <AFormItem :label="$gettext('Terminal Start Command')">
       <p>{{ data.terminal.start_cmd }}</p>
     </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
       :label="$gettext('Github Proxy')"
       :validate-status="errors?.http?.github_proxy ? 'error' : ''"
@@ -39,13 +48,28 @@ const errors: Record<string, Record<string, string>> = inject('errors') as Recor
       />
     </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.')"
+      :label="$gettext('ICP Number')"
+      :validate-status="errors?.node?.icp_number ? 'error' : ''"
+      :help="errors?.node?.icp_number.includes('safety_text')
+        ? $gettext('The ICP Number should only contain letters, unicode, numbers, hyphens, dashes, and dots.')
+        : ''"
     >
-      <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>
   </AForm>
 </template>

+ 13 - 0
docs/zh_CN/guide/config-node.md

@@ -23,3 +23,16 @@
 
 默认情况下,如果您启用了跳过安装模式,而没有在服务器部分设置 `App.JwtSecret` 和 `Node.Secret` 选项,
 Nginx UI 将为这两个选项生成一个随机的 UUID 值。
+
+## ICPNumber
+- 类型: `string`
+- 版本: `>= v2.0.0-beta.42`
+
+此选项用于设置 ICP 备案号。
+
+## PublicSecurityNumber
+- 类型: `string`
+- 版本: `>= v2.0.0-beta.42`
+
+此选项用于设置 ICP 备案号。
+

+ 2 - 0
router/routers.go

@@ -8,6 +8,7 @@ import (
 	"github.com/0xJacky/Nginx-UI/api/nginx"
 	"github.com/0xJacky/Nginx-UI/api/notification"
 	"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/sites"
 	"github.com/0xJacky/Nginx-UI/api/streams"
@@ -39,6 +40,7 @@ func InitRouter() {
 
 	root := r.Group("/api")
 	{
+		public.InitRouter(root)
 		system.InitPublicRouter(root)
 		user.InitAuthRouter(root)
 

+ 1 - 4
settings/http.go

@@ -5,7 +5,4 @@ type HTTP struct {
 	InsecureSkipVerify bool   `json:"insecure_skip_verify" protected:"true"`
 }
 
-var HTTPSettings = &HTTP{
-	GithubProxy:        "",
-	InsecureSkipVerify: false,
-}
+var HTTPSettings = &HTTP{}

+ 1 - 4
settings/nginx.go

@@ -11,7 +11,4 @@ type Nginx struct {
 	RestartCmd      string   `json:"restart_cmd" protected:"true"`
 }
 
-var NginxSettings = &Nginx{
-	AccessLogPath: "",
-	ErrorLogPath:  "",
-}
+var NginxSettings = &Nginx{}

+ 7 - 10
settings/node.go

@@ -1,15 +1,12 @@
 package settings
 
 type Node struct {
-	Name             string `json:"name" binding:"omitempty,safety_text"`
-	Secret           string `json:"secret" protected:"true"`
-	SkipInstallation bool   `json:"skip_installation" protected:"true"`
-	Demo             bool   `json:"demo" protected:"true"`
+	Name                 string `json:"name" binding:"omitempty,safety_text"`
+	Secret               string `json:"secret" protected:"true"`
+	SkipInstallation     bool   `json:"skip_installation" 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{
-	Name:             "",
-	Secret:           "",
-	SkipInstallation: false,
-	Demo:             false,
-}
+var NodeSettings = &Node{}