From 8622f2b7b2874bbb3efa1bf5ef6a9b9e077ae2fc Mon Sep 17 00:00:00 2001 From: yiqiu Date: Fri, 21 Nov 2025 00:25:11 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=92=E4=BB=B6UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../template/admin/index.html | 266 +++++++++++++++--- .../template/admin/theme.css | 72 ++++- 2 files changed, 292 insertions(+), 46 deletions(-) diff --git a/plugins/addon/theme_configurator/template/admin/index.html b/plugins/addon/theme_configurator/template/admin/index.html index 2de3b5a..1872161 100644 --- a/plugins/addon/theme_configurator/template/admin/index.html +++ b/plugins/addon/theme_configurator/template/admin/index.html @@ -2,29 +2,134 @@
- -
-
-

主题配置

-

- 在此集中维护 BlackFruit-UI 的导航、页脚、SEO、企业信息、轮播和侧边浮窗等配置。 -

+ +
+
+ +
-
- - 刷新 - - - 保存 - +
+ + +
+
+ +
- -

- JSON 结构与 `/console/v1/common` 返回值保持一致,保存后即可供前台调用。 -

+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
还没有轮播图,点击下方按钮添加。
+ + 新增轮播 +
+ + +

+ 用于暂未在 UI 中开放的配置项(如导航结构、友情链接等)。可先点击“同步当前配置”再做修改。 +

+ +
+ 同步当前配置 + 应用 JSON +
+
+ +
+ 重新加载 + 保存全部配置 +
@@ -35,20 +140,88 @@ const adminPath = location.pathname.split("/")[1]; const base = `${host}/${adminPath}/v1/theme/config`; + const showMessage = (vm, type, text) => { + if (vm.$message && typeof vm.$message[type] === "function") { + vm.$message[type](text); + } else if (window.MessagePlugin && typeof window.MessagePlugin[type] === "function") { + window.MessagePlugin[type](text); + } else { + alert(text); + } + }; + + const createDefaultConfig = () => ({ + seo: { + title: "", + keywords: "", + description: "", + }, + site_config: { + enterprise_name: "", + enterprise_telephone: "", + enterprise_mailbox: "", + enterprise_qrcode: "", + official_website_logo: "", + icp_info: "", + icp_info_link: "", + public_security_network_preparation: "", + public_security_network_preparation_link: "", + telecom_appreciation: "", + copyright_info: "", + }, + banner: [], + header_nav: [], + footer_nav: [], + friendly_link: [], + side: [], + feedback_type: [], + }); + new Vue({ el: "#theme-config-app", data() { return { - configText: "", loading: false, saving: false, - langPlaceholder: "请严格按照 JSON 格式填写主题配置...", + fullConfig: createDefaultConfig(), + advancedText: "", }; }, - created() { - this.loadConfig(); + computed: { + bannerList() { + if (!Array.isArray(this.fullConfig.banner)) { + this.fullConfig.banner = []; + } + return this.fullConfig.banner; + }, }, methods: { + normalizeConfig(data = {}) { + const defaults = createDefaultConfig(); + return { + ...defaults, + ...data, + seo: { + ...defaults.seo, + ...(data.seo || {}), + }, + site_config: { + ...defaults.site_config, + ...(data.site_config || {}), + }, + banner: Array.isArray(data.banner) ? data.banner : [], + header_nav: Array.isArray(data.header_nav) ? data.header_nav : [], + footer_nav: Array.isArray(data.footer_nav) ? data.footer_nav : [], + friendly_link: Array.isArray(data.friendly_link) ? data.friendly_link : [], + side: + Array.isArray(data.side) + ? data.side + : Array.isArray(data.side_floating_window) + ? data.side_floating_window + : [], + feedback_type: Array.isArray(data.feedback_type) ? data.feedback_type : [], + }; + }, loadConfig() { this.loading = true; axios @@ -59,23 +232,49 @@ }) .then((res) => { const data = (res.data && res.data.data) || {}; - this.configText = JSON.stringify(data, null, 2); + this.fullConfig = this.normalizeConfig(data); + this.syncJson(); }) .finally(() => { this.loading = false; }); }, - saveConfig() { - if (!this.configText.trim()) { - return this.$message.warning("内容不能为空"); + syncJson() { + this.advancedText = JSON.stringify(this.fullConfig, null, 2); + }, + applyAdvanced() { + if (!this.advancedText.trim()) { + return showMessage(this, "warning", "JSON 内容为空"); } - let payload; try { - payload = JSON.parse(this.configText); + const parsed = JSON.parse(this.advancedText); + this.fullConfig = this.normalizeConfig(parsed); + showMessage(this, "success", "JSON 已应用"); } catch (err) { - return this.$message.error("JSON 解析失败:" + err.message); + showMessage(this, "error", "JSON 解析失败:" + err.message); } + }, + addBanner() { + this.bannerList.push({ + title: "", + description: "", + img: "", + url: "", + blank: false, + button_text: "", + button_link: "", + button_blank: false, + }); + }, + removeBanner(index) { + this.bannerList.splice(index, 1); + }, + saveConfig() { this.saving = true; + const payload = { + ...this.fullConfig, + side_floating_window: this.fullConfig.side || [], + }; axios .post(base, payload, { headers: { @@ -83,14 +282,17 @@ }, }) .then((res) => { - this.$message.success(res.data.msg || "保存成功"); - this.configText = JSON.stringify(res.data.data, null, 2); + showMessage(this, "success", (res.data && res.data.msg) || "保存成功"); + this.loadConfig(); }) .finally(() => { this.saving = false; }); }, }, + mounted() { + this.loadConfig(); + }, }); })(); diff --git a/plugins/addon/theme_configurator/template/admin/theme.css b/plugins/addon/theme_configurator/template/admin/theme.css index dc19c43..d1913f5 100644 --- a/plugins/addon/theme_configurator/template/admin/theme.css +++ b/plugins/addon/theme_configurator/template/admin/theme.css @@ -1,22 +1,26 @@ .theme-card { - margin: 20px; -} - -.theme-card__header { - display: flex; - justify-content: space-between; - align-items: center; margin-bottom: 20px; } -.theme-card__header h3 { - margin: 0; - font-size: 20px; +.form-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); + grid-gap: 16px; } -.theme-desc { - margin: 4px 0 0; +.form-item { + display: flex; + flex-direction: column; +} + +.form-item--full { + grid-column: 1 / -1; +} + +.form-item label { + font-size: 13px; color: #6b7280; + margin-bottom: 6px; } .theme-textarea textarea { @@ -24,11 +28,51 @@ } .theme-tip { - margin-top: 12px; - color: #9ca3af; + margin-top: 0; + margin-bottom: 12px; + color: #94a3b8; font-size: 12px; } +.banner-item { + border: 1px solid #e5e7eb; + border-radius: 8px; + padding: 16px; + margin-bottom: 16px; + background: #f9fafb; +} + +.banner-item__header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 16px; +} + +.banner-item__header h4 { + margin: 0; + font-size: 16px; +} + +.empty-tip { + padding: 16px; + border: 1px dashed #cbd5f5; + border-radius: 6px; + color: #6b7280; + margin-bottom: 16px; + background: #f8fafc; +} + +.action-bar { + display: flex; + justify-content: flex-end; + margin-top: 20px; +} + +.mt-10 { + margin-top: 10px; +} + .ml-10 { margin-left: 10px; }