From 5834ab9a7489ff84b47295d7f53c3aa9df072953 Mon Sep 17 00:00:00 2001 From: yiqiu Date: Fri, 21 Nov 2025 12:42:18 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=8F=92=E4=BB=B6UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/common.js | 42 +-- js/about.js | 19 +- js/feedback.js | 59 +++-- js/index.js | 42 +-- plugins/addon/theme_configurator/README.md | 13 +- .../controller/ThemeController.php | 4 + .../controller/clientarea/ThemeController.php | 7 +- .../model/ThemeConfigModel.php | 15 +- .../template/admin/index.html | 244 +++++++++++++++++- .../template/admin/theme.css | 28 ++ 10 files changed, 403 insertions(+), 70 deletions(-) diff --git a/common/common.js b/common/common.js index 8a5fdce..11d3a30 100644 --- a/common/common.js +++ b/common/common.js @@ -105,21 +105,33 @@ $(function () { $(".login-in").attr("style", "display:none"); $(".no-login").attr("style", "display:block"); } - }; - // 获取通用配置信息 - const getCommentInfo = () => { - $.ajax({ - url: "/console/v1/common", - method: "get", - headers: { - Authorization: "Bearer" + " " + localStorage.jwt, - }, - success: function (res) { - sessionStorage.commentData = JSON.stringify(res.data); - setCommData(); - }, - }); - }; + }; + // 获取通用配置信息 + const getCommentInfo = () => { + const handleSuccess = function (res) { + sessionStorage.commentData = JSON.stringify(res.data); + setCommData(); + }; + $.ajax({ + url: "/console/v1/theme/config", + method: "get", + headers: { + Authorization: "Bearer" + " " + localStorage.jwt, + }, + success: handleSuccess, + error: function () { + // 若插件接口不存在或报错,回落到原有 /console/v1/common + $.ajax({ + url: "/console/v1/common", + method: "get", + headers: { + Authorization: "Bearer" + " " + localStorage.jwt, + }, + success: handleSuccess, + }); + }, + }); + }; // 设置通用信息函数 const setCommData = () => { const commentObj = JSON.parse(sessionStorage.commentData); diff --git a/js/about.js b/js/about.js index d39d417..61a2a02 100644 --- a/js/about.js +++ b/js/about.js @@ -22,15 +22,26 @@ $(function () { // 获取通用配置信息 function getCommentInfo() { + const handleSuccess = function (res) { + sessionStorage.commentData = JSON.stringify(res.data); + setIndexData(); + }; $.ajax({ - url: "/console/v1/common", + url: "/console/v1/theme/config", method: "get", headers: { Authorization: "Bearer" + " " + localStorage.jwt, }, - success: function (res) { - sessionStorage.commentData = JSON.stringify(res.data); - setIndexData(); + success: handleSuccess, + error: function () { + $.ajax({ + url: "/console/v1/common", + method: "get", + headers: { + Authorization: "Bearer" + " " + localStorage.jwt, + }, + success: handleSuccess, + }); }, }); } diff --git a/js/feedback.js b/js/feedback.js index fa7be54..1d49553 100644 --- a/js/feedback.js +++ b/js/feedback.js @@ -56,28 +56,39 @@ $(function () { } // 表单元素必填验证函数 - function validateRequired(input) { - if (input.val().trim() === "") { - input.attr("style", "border: 1px solid #FF6739;"); - input.focus(); - return false; + function validateRequired(input) { + if (input.val().trim() === "") { + input.attr("style", "border: 1px solid #FF6739;"); + input.focus(); + return false; } - input.attr("style", "border: 1px solid #E6EAED;"); - return true; - } - // 获取通用配置信息 - function getCommentInfo() { - $.ajax({ - url: "/console/v1/common", - method: "get", - headers: { - Authorization: "Bearer" + " " + localStorage.jwt, - }, - success: function (res) { - sessionStorage.commentData = JSON.stringify(res.data); - setIndexData(); - }, - }); - } - getCommentInfo(); -}); + input.attr("style", "border: 1px solid #E6EAED;"); + return true; + } + // 获取通用配置信息 + function getCommentInfo() { + const handleSuccess = function (res) { + sessionStorage.commentData = JSON.stringify(res.data); + setIndexData(); + }; + $.ajax({ + url: "/console/v1/theme/config", + method: "get", + headers: { + Authorization: "Bearer" + " " + localStorage.jwt, + }, + success: handleSuccess, + error: function () { + $.ajax({ + url: "/console/v1/common", + method: "get", + headers: { + Authorization: "Bearer" + " " + localStorage.jwt, + }, + success: handleSuccess, + }); + }, + }); + } + getCommentInfo(); +}); diff --git a/js/index.js b/js/index.js index 983ba79..a099d04 100644 --- a/js/index.js +++ b/js/index.js @@ -127,21 +127,33 @@ $(function () { `); }); } - } - // 获取通用配置信息 - function getCommentInfo() { - $.ajax({ - url: "/console/v1/common", - method: "get", - headers: { - Authorization: "Bearer" + " " + localStorage.jwt, - }, - success: function (res) { - sessionStorage.commentData = JSON.stringify(res.data); - setIndexData(); - }, - }); - } + } + // 获取通用配置信息 + function getCommentInfo() { + const handleSuccess = function (res) { + sessionStorage.commentData = JSON.stringify(res.data); + setIndexData(); + }; + $.ajax({ + url: "/console/v1/theme/config", + method: "get", + headers: { + Authorization: "Bearer" + " " + localStorage.jwt, + }, + success: handleSuccess, + error: function () { + // 插件未启用时回落到原有 /console/v1/common + $.ajax({ + url: "/console/v1/common", + method: "get", + headers: { + Authorization: "Bearer" + " " + localStorage.jwt, + }, + success: handleSuccess, + }); + }, + }); + } // 获取首页数据 getCommentInfo(); var viewer = new Viewer(document.getElementById("viewer"), { diff --git a/plugins/addon/theme_configurator/README.md b/plugins/addon/theme_configurator/README.md index 7634860..4b52f0a 100644 --- a/plugins/addon/theme_configurator/README.md +++ b/plugins/addon/theme_configurator/README.md @@ -1,11 +1,18 @@ # Theme Configurator 插件 -此插件演示如何通过后台插件的方式为 BlackFruit-UI 主题提供可配置能力,支持设置导航、页脚、站点信息、SEO、首页轮播以及右侧浮窗,并提供 `/console/v1/theme/config` 接口与前端联动。 +此插件演示如何通过后台插件的方式为 BlackFruit-UI 主题提供可配置能力,支持设置导航、页脚、站点信息、SEO、首页轮播、友情链接、荣誉/合作伙伴、反馈类型以及右侧浮窗,并提供 `/console/v1/theme/config` 接口与前端联动。 ## 功能 -- 后台界面(`template/admin/index.html`)以 JSON 的形式集中维护所有主题参数; +- 后台界面(`template/admin/index.html`)通过表单 + JSON 的方式维护主题参数: + - SEO、站点基础信息(企业名称、电话、备案、协议链接、产品链接等); + - 首页轮播 Banner; + - 友情链接(friendly_link); + - 企业荣誉(honor)、合作伙伴/成功案例(partner); + - 反馈类型(feedback_type); + - 右侧浮窗(side / side_floating_window); + - 复杂导航结构(header_nav/footer_nav)可在“高级配置 (JSON)”中维护。 - 接口 `GET/POST /{DIR_ADMIN}/v1/theme/config` 提供配置读取与保存; -- 前台接口 `GET /console/v1/theme/config` 输出与 `/console/v1/common` 相同结构的数据,BlackFruit-UI 可以直接接入; +- 前台接口 `GET /console/v1/theme/config` 输出与 `/console/v1/common` 同结构的数据,BlackFruit-UI 可以直接接入; - 插件安装时创建 `addon_theme_configurator` 表并写入默认配置。 ## 目录 diff --git a/plugins/addon/theme_configurator/controller/ThemeController.php b/plugins/addon/theme_configurator/controller/ThemeController.php index 8c9f4c1..155e3b2 100644 --- a/plugins/addon/theme_configurator/controller/ThemeController.php +++ b/plugins/addon/theme_configurator/controller/ThemeController.php @@ -45,6 +45,10 @@ class ThemeController extends PluginAdminBaseController 'friendly_link' => $param['friendly_link'] ?? [], 'banner' => $param['banner'] ?? [], 'side' => $param['side'] ?? [], + // 额外配置:荣誉、合作伙伴、反馈类型 + 'feedback_type' => $param['feedback_type'] ?? [], + 'honor' => $param['honor'] ?? [], + 'partner' => $param['partner'] ?? [], ]; $config = $this->model->saveConfig($payload); diff --git a/plugins/addon/theme_configurator/controller/clientarea/ThemeController.php b/plugins/addon/theme_configurator/controller/clientarea/ThemeController.php index fe97856..4571b49 100644 --- a/plugins/addon/theme_configurator/controller/clientarea/ThemeController.php +++ b/plugins/addon/theme_configurator/controller/clientarea/ThemeController.php @@ -42,14 +42,15 @@ class ThemeController extends PluginBaseController 'terms_privacy_url' => $config['site_config']['terms_privacy_url'] ?? '', 'cloud_product_link' => $config['site_config']['cloud_product_link'] ?? '', 'dcim_product_link' => $config['site_config']['dcim_product_link'] ?? '', - 'honor' => $config['site_config']['honor'] ?? [], - 'partner' => $config['site_config']['partner'] ?? [], + // 以下字段需与 /console/v1/common 保持一致的扁平结构 + 'honor' => $config['honor'] ?? ($config['site_config']['honor'] ?? []), + 'partner' => $config['partner'] ?? ($config['site_config']['partner'] ?? []), 'friendly_link' => $config['friendly_link'] ?? [], 'banner' => $config['banner'] ?? [], 'header_nav' => $config['header_nav'] ?? [], 'footer_nav' => $config['footer_nav'] ?? [], 'side_floating_window' => $config['side'] ?? [], - 'feedback_type' => $config['site_config']['feedback_type'] ?? [], + 'feedback_type' => $config['feedback_type'] ?? ($config['site_config']['feedback_type'] ?? []), ]; return json([ diff --git a/plugins/addon/theme_configurator/model/ThemeConfigModel.php b/plugins/addon/theme_configurator/model/ThemeConfigModel.php index a384b1a..0ee53b8 100644 --- a/plugins/addon/theme_configurator/model/ThemeConfigModel.php +++ b/plugins/addon/theme_configurator/model/ThemeConfigModel.php @@ -75,14 +75,16 @@ class ThemeConfigModel protected function defaultConfig(): array { return [ - 'seo' => [ + 'seo' => [ 'title' => 'BlackFruit-UI', 'keywords' => '云服务器,主题云,BlackFruit', 'description' => 'BlackFruit-UI 默认站点说明', ], - 'header_nav' => [], - 'footer_nav' => [], - 'site_config' => [ + // 顶部/底部导航 + 'header_nav' => [], + 'footer_nav' => [], + // 站点基础信息 + 'site_config' => [ 'enterprise_name' => '主题云', 'enterprise_telephone' => '400-000-0000', 'enterprise_mailbox' => 'support@example.com', @@ -99,9 +101,14 @@ class ThemeConfigModel 'cloud_product_link' => '/cart/goods.htm?id=1', 'dcim_product_link' => '/cart/goods.htm?id=2', ], + // 友情链接、轮播、侧边浮窗等 'friendly_link' => [], 'banner' => [], 'side' => [], + // 用于 /console/v1/common 的扩展字段 + 'feedback_type' => [], + 'honor' => [], + 'partner' => [], ]; } } diff --git a/plugins/addon/theme_configurator/template/admin/index.html b/plugins/addon/theme_configurator/template/admin/index.html index 1872161..da1ee91 100644 --- a/plugins/addon/theme_configurator/template/admin/index.html +++ b/plugins/addon/theme_configurator/template/admin/index.html @@ -61,6 +61,26 @@ v-model="fullConfig.site_config.public_security_network_preparation_link" placeholder="https://beian.mps.gov.cn"> +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
@@ -115,9 +135,146 @@ 新增轮播 + +
还没有友情链接,点击下方按钮添加。
+
+
+

链接 {{ index + 1 }}

+ + 删除 + +
+
+
+ + +
+
+ + +
+
+
+ 新增友情链接 +
+ + +

企业荣誉

+
用于首页“荣誉资质”模块(honor)。
+
+
+

荣誉 {{ index + 1 }}

+ + 删除 + +
+
+
+ + +
+
+ + +
+
+
+ 新增荣誉 + +

合作伙伴/成功案例

+
用于首页“典型案例/合作伙伴”模块(partner)。
+
+
+

伙伴 {{ index + 1 }}

+ + 删除 + +
+
+
+ + +
+
+ + +
+
+ + +
+
+
+ 新增合作伙伴 +
+ + +

+ 对应 /console/v1/feedback 的类型选项,ID 需与后端保持一致,仅建议修改名称与描述。 +

+
还没有反馈类型,点击下方按钮添加。
+
+
+

类型 {{ index + 1 }}

+ + 删除 + +
+
+
+ + +
+
+ + +
+
+ + +
+
+
+ 新增反馈类型 +
+ + +

+ 对应前台右侧悬浮工具条(电话咨询/在线客服/提交工单等),结构与模板中的 side_floating_window 一致。 +

+
还没有侧边浮窗,点击下方按钮添加。
+
+
+

浮窗 {{ index + 1 }}

+ + 删除 + +
+
+
+ + +
+
+ + +
+
+ + +
+
+
+ 新增浮窗 +
+

- 用于暂未在 UI 中开放的配置项(如导航结构、友情链接等)。可先点击“同步当前配置”再做修改。 + 用于暂未在 UI 中开放的配置项(如复杂导航结构 header_nav/footer_nav 等)。如非必要,建议优先使用上方表单编辑。

@@ -168,6 +325,10 @@ public_security_network_preparation_link: "", telecom_appreciation: "", copyright_info: "", + terms_service_url: "", + terms_privacy_url: "", + cloud_product_link: "", + dcim_product_link: "", }, banner: [], header_nav: [], @@ -175,6 +336,8 @@ friendly_link: [], side: [], feedback_type: [], + honor: [], + partner: [], }); new Vue({ @@ -219,7 +382,21 @@ : Array.isArray(data.side_floating_window) ? data.side_floating_window : [], - feedback_type: Array.isArray(data.feedback_type) ? data.feedback_type : [], + feedback_type: Array.isArray(data.feedback_type) + ? data.feedback_type + : Array.isArray(data.site_config && data.site_config.feedback_type) + ? data.site_config.feedback_type + : [], + honor: Array.isArray(data.honor) + ? data.honor + : Array.isArray(data.site_config && data.site_config.honor) + ? data.site_config.honor + : [], + partner: Array.isArray(data.partner) + ? data.partner + : Array.isArray(data.site_config && data.site_config.partner) + ? data.site_config.partner + : [], }; }, loadConfig() { @@ -269,6 +446,69 @@ removeBanner(index) { this.bannerList.splice(index, 1); }, + addFriendlyLink() { + if (!Array.isArray(this.fullConfig.friendly_link)) { + this.fullConfig.friendly_link = []; + } + this.fullConfig.friendly_link.push({ + name: "", + url: "", + }); + }, + removeFriendlyLink(index) { + this.fullConfig.friendly_link.splice(index, 1); + }, + addHonor() { + if (!Array.isArray(this.fullConfig.honor)) { + this.fullConfig.honor = []; + } + this.fullConfig.honor.push({ + name: "", + img: "", + }); + }, + removeHonor(index) { + this.fullConfig.honor.splice(index, 1); + }, + addPartner() { + if (!Array.isArray(this.fullConfig.partner)) { + this.fullConfig.partner = []; + } + this.fullConfig.partner.push({ + name: "", + img: "", + description: "", + }); + }, + removePartner(index) { + this.fullConfig.partner.splice(index, 1); + }, + addFeedbackType() { + if (!Array.isArray(this.fullConfig.feedback_type)) { + this.fullConfig.feedback_type = []; + } + this.fullConfig.feedback_type.push({ + id: "", + name: "", + description: "", + }); + }, + removeFeedbackType(index) { + this.fullConfig.feedback_type.splice(index, 1); + }, + addSide() { + if (!Array.isArray(this.fullConfig.side)) { + this.fullConfig.side = []; + } + this.fullConfig.side.push({ + name: "", + icon: "", + content: "", + }); + }, + removeSide(index) { + this.fullConfig.side.splice(index, 1); + }, saveConfig() { this.saving = true; const payload = { diff --git a/plugins/addon/theme_configurator/template/admin/theme.css b/plugins/addon/theme_configurator/template/admin/theme.css index d1913f5..e964046 100644 --- a/plugins/addon/theme_configurator/template/admin/theme.css +++ b/plugins/addon/theme_configurator/template/admin/theme.css @@ -54,6 +54,34 @@ font-size: 16px; } +/* 通用列表块,复用轮播样式 */ +.config-item { + border: 1px solid #e5e7eb; + border-radius: 8px; + padding: 16px; + margin-bottom: 16px; + background: #f9fafb; +} + +.config-item__header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 16px; +} + +.config-item__header h4 { + margin: 0; + font-size: 16px; +} + +.sub-title { + margin: 0 0 8px; + font-size: 14px; + font-weight: 600; + color: #4b5563; +} + .empty-tip { padding: 16px; border: 1px dashed #cbd5f5;