Selaa lähdekoodia

重构siteinfo

tsurumure 8 kuukautta sitten
vanhempi
commit
122014475a
33 muutettua tiedostoa jossa 828 lisäystä ja 125 poistoa
  1. 3 2
      db/sys_user_role_module.sql
  2. 2 2
      db/sys_user_role_module_relation.sql
  3. 14 14
      src/main/java/com/backendsys/controller/RedirectController.java
  4. 2 10
      src/main/java/com/backendsys/modules/cms/pageArticle/controller/PageArticleController.java
  5. 43 0
      src/main/java/com/backendsys/modules/cms/pageHome/controller/PageHomeController.java
  6. 47 0
      src/main/java/com/backendsys/modules/cms/siteinfo/controller/SiteInfoController.java
  7. 9 0
      src/main/java/com/backendsys/modules/cms/siteinfo/dao/SiteInfoDao.java
  8. 44 0
      src/main/java/com/backendsys/modules/cms/siteinfo/entity/SiteInfo.java
  9. 15 0
      src/main/java/com/backendsys/modules/cms/siteinfo/service/SiteInfoService.java
  10. 34 0
      src/main/java/com/backendsys/modules/cms/siteinfo/service/impl/SiteInfoServiceImpl.java
  11. 11 11
      src/main/java/com/backendsys/modules/common/config/security/CorsConfig.java
  12. 10 0
      src/main/java/com/backendsys/modules/common/utils/views/MvcRequest.java
  13. 43 0
      src/main/java/com/backendsys/modules/common/utils/views/MvcUtil.java
  14. 97 0
      src/main/resources/__templates/__article.html
  15. 24 0
      src/main/resources/__templates/__layout/head.html
  16. 73 0
      src/main/resources/__templates/__layout/layout-footer.html
  17. 61 0
      src/main/resources/__templates/__layout/layout-header.html
  18. 8 0
      src/main/resources/__templates/__layout/layout-top.html
  19. 10 0
      src/main/resources/__templates/__layout/layout.html
  20. 3 0
      src/main/resources/__templates/article.html
  21. 68 0
      src/main/resources/__templates/articleDetail.html
  22. 20 0
      src/main/resources/__templates/components/language.html
  23. 22 0
      src/main/resources/__templates/components/search-input.html
  24. 2 0
      src/main/resources/__templates/components/sub-banner.html
  25. 16 0
      src/main/resources/__templates/error.html
  26. 88 0
      src/main/resources/__templates/index.html
  27. 8 0
      src/main/resources/__templates/layout/head.html
  28. 3 0
      src/main/resources/__templates/layout/layout-footer.html
  29. 3 0
      src/main/resources/__templates/layout/layout-header.html
  30. 3 0
      src/main/resources/__templates/layout/layout-top.html
  31. 10 0
      src/main/resources/__templates/layout/layout.html
  32. 31 0
      src/main/resources/__templates/page.html
  33. 1 86
      src/main/resources/templates/index.html

+ 3 - 2
db/sys_user_role_module.sql

@@ -130,8 +130,9 @@ INSERT INTO sys_user_role_module(id, parent_id, module_name, sort) VALUES
     --     ('12.1', '12', '内容-列表', null),
     --     ('12.2', '12', '内容-详情', null),
     --     ('12.3', '12', '内容-编辑', null),
-    -- ('13', -1, '站点管理', null),
-    --     ('13.1', '13', '站点-编辑', null),
+
+    ('13', -1, '站点管理', null),
+        ('13.1', '13', '站点-编辑', null),
 
     ('20', -1, '素材管理', null),
         ('20.1', '20', '素材列表', null),

+ 2 - 2
db/sys_user_role_module_relation.sql

@@ -62,8 +62,8 @@ INSERT INTO sys_user_role_module_relation(role_id, module_id) VALUES
 #         (1, '12.1'),
 #         (1, '12.2'),
 #         (1, '12.3'),
-#     (1, '13'),
-#         (1, '13.1'),
+    (1, '13'),
+        (1, '13.1'),
 
     (1, '20'),
         (1, '20.1'),

+ 14 - 14
src/main/java/com/backendsys/controller/RedirectController.java

@@ -1,14 +1,14 @@
-package com.backendsys.controller;
-
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-@RestController
-public class RedirectController {
-
-    @GetMapping("/")
-    public String redirectRoot() {
-        return "";
-    }
-
-}
+//package com.backendsys.controller;
+//
+//import org.springframework.web.bind.annotation.GetMapping;
+//import org.springframework.web.bind.annotation.RestController;
+//
+//@RestController
+//public class RedirectController {
+//
+//    @GetMapping("/")
+//    public String redirectRoot() {
+//        return "";
+//    }
+//
+//}

+ 2 - 10
src/main/java/com/backendsys/modules/cms/article/controller/AppArticleController.java → src/main/java/com/backendsys/modules/cms/pageArticle/controller/PageArticleController.java

@@ -1,21 +1,13 @@
-package com.backendsys.modules.cms.article.controller;
+package com.backendsys.modules.cms.pageArticle.controller;
 
-import com.backendsys.modules.common.config.security.annotations.Anonymous;
 import jakarta.servlet.http.HttpServletRequest;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * 关于我们
- */
 @Controller
-public class AppArticleController {
+public class PageArticleController {
 
 //    @Autowired
 //    private CmsSiteInfoService cmsSiteInfoService;

+ 43 - 0
src/main/java/com/backendsys/modules/cms/pageHome/controller/PageHomeController.java

@@ -0,0 +1,43 @@
+package com.backendsys.modules.cms.pageHome.controller;
+
+import com.backendsys.modules.cms.siteinfo.service.SiteInfoService;
+import jakarta.servlet.http.HttpServletRequest;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.GetMapping;
+
+@Controller
+public class PageHomeController {
+
+    @Autowired
+    private SiteInfoService siteInfoService;
+
+    @GetMapping({"/"})
+    public String home(Model model, HttpServletRequest request) {
+//        // -- 初始化公共事件 ---------------------------------------------
+//        RequestUtil.initResponse(model, request, cmsSiteInfoService, cmsNavigationService);
+//        // -- Header ---------------------------------------------
+//        model.addAttribute("title","首页");
+//        // -------------------------------------------------------
+//        model.addAttribute("bannerList", cmsBannerService.queryBannerPublic());
+//
+//        CmsArticleDTO cmsArticleDTO = new CmsArticleDTO();
+//        cmsArticleDTO.setLang((String) model.getAttribute("lang"));
+//
+//        // 分类1
+//        cmsArticleDTO.setCategory_id(1L);
+//        Map<String, Object> list1 = cmsArticleService.queryArticle(1, 4, cmsArticleDTO);
+//        model.addAttribute("articleList1", list1);
+//
+//        // 分类2
+//        cmsArticleDTO.setCategory_id(2L);
+//        Map<String, Object> list2 = cmsArticleService.queryArticle(1, 4, cmsArticleDTO);
+//        model.addAttribute("articleList2", list2);
+
+        // -- Layout ---------------------------------------------
+        model.addAttribute("layout", "index");
+        return "layout/layout";
+    }
+
+}

+ 47 - 0
src/main/java/com/backendsys/modules/cms/siteinfo/controller/SiteInfoController.java

@@ -0,0 +1,47 @@
+package com.backendsys.modules.cms.siteinfo.controller;
+
+import com.backendsys.entity.Cms.CmsSiteInfoDTO;
+import com.backendsys.modules.cms.siteinfo.entity.SiteInfo;
+import com.backendsys.modules.cms.siteinfo.service.SiteInfoService;
+import com.backendsys.modules.common.utils.Result;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+@Validated
+@RestController
+@Tag(name = "站点管理")
+public class SiteInfoController {
+
+    @Autowired
+    private SiteInfoService siteInfoService;
+
+    @Operation(summary = "获取站点信息")
+    @PreAuthorize("@ss.hasPermi('13')")
+    @GetMapping("/api/v2/cms/site/getSiteInfo")
+    public Result getSiteInfo() {
+        SiteInfo siteInfo = new SiteInfo();
+        siteInfo.setId(1L);
+        return Result.success().put("data", siteInfoService.selectSiteInfo(siteInfo));
+    }
+
+//
+//    @GetMapping("/api/public/cms/site/getSiteInfo")
+//    public Result getSiteInfoPublic(@Validated CmsSiteInfoDTO cmsSiteInfoDTO) {
+//        return Result.success(cmsSiteInfoService.querySiteInfo(cmsSiteInfoDTO));
+//    }
+
+    @PreAuthorize("@ss.hasPermi('13.1')")
+    @PutMapping("/api/v2/cms/site/updateSiteInfo")
+    public Result updateSiteInfo(@Validated(SiteInfo.Update.class) @RequestBody SiteInfo siteInfo) {
+        siteInfo.setId(1L);
+        return Result.success().put("data", siteInfoService.updateSiteInfo(siteInfo));
+    }
+
+}

+ 9 - 0
src/main/java/com/backendsys/modules/cms/siteinfo/dao/SiteInfoDao.java

@@ -0,0 +1,9 @@
+package com.backendsys.modules.cms.siteinfo.dao;
+
+import com.backendsys.modules.cms.siteinfo.entity.SiteInfo;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface SiteInfoDao extends BaseMapper<SiteInfo> {
+}

+ 44 - 0
src/main/java/com/backendsys/modules/cms/siteinfo/entity/SiteInfo.java

@@ -0,0 +1,44 @@
+package com.backendsys.modules.cms.siteinfo.entity;
+
+import com.backendsys.entity.validator.RangeArray;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+@Data
+@TableName("cms_site_info")
+public class SiteInfo {
+
+    public static interface Detail{}
+    public static interface Update{}
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    @NotEmpty(message="网站名称不能为空", groups = { Update.class })
+    @Size(min = 2, max = 20, message = "网站名称长度在 {min}-{max} 字符", groups = { Update.class })
+    private String name;
+
+    @Size(max = 100, message = "关键词长度不超过 {max} 字符", groups = { Update.class })
+    private String meta_keyword;
+    @Size(max = 200, message = "关键词描述长度不超过 {max} 字符", groups = { Update.class })
+    private String meta_description;
+
+    @Size(max = 100, message = "版权信息长度不超过 {max} 字符", groups = { Update.class })
+    private String copyright;
+
+    @Size(max = 20, message = "备案信息长度不超过 {max} 字符", groups = { Update.class })
+    private String icp;
+
+    @RangeArray(message="状态取值有误,范围应是(-1禁用, 1启用)", value = {"-1", "1"}, groups = { Update.class })
+    private Integer status;
+
+    private String create_time;
+    private String update_time;
+
+}

+ 15 - 0
src/main/java/com/backendsys/modules/cms/siteinfo/service/SiteInfoService.java

@@ -0,0 +1,15 @@
+package com.backendsys.modules.cms.siteinfo.service;
+
+
+import com.backendsys.modules.cms.siteinfo.entity.SiteInfo;
+
+import java.util.Map;
+
+public interface SiteInfoService {
+
+    // 获取站点信息
+    SiteInfo selectSiteInfo(SiteInfo siteInfo);
+    // 更新站点信息
+    Map<String, Object> updateSiteInfo(SiteInfo siteInfo);
+
+}

+ 34 - 0
src/main/java/com/backendsys/modules/cms/siteinfo/service/impl/SiteInfoServiceImpl.java

@@ -0,0 +1,34 @@
+package com.backendsys.modules.cms.siteinfo.service.impl;
+
+import com.backendsys.modules.cms.siteinfo.dao.SiteInfoDao;
+import com.backendsys.modules.cms.siteinfo.entity.SiteInfo;
+import com.backendsys.modules.cms.siteinfo.service.SiteInfoService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Map;
+
+@Service
+public class SiteInfoServiceImpl implements SiteInfoService {
+
+    @Autowired
+    private SiteInfoDao siteInfoDao;
+
+    /**
+     * 获取站点信息
+     */
+    @Override
+    public SiteInfo selectSiteInfo(SiteInfo siteInfo) {
+        return siteInfoDao.selectById(siteInfo.getId());
+    }
+
+    /**
+     * 更新站点信息
+     */
+    @Override
+    public Map<String, Object> updateSiteInfo(SiteInfo siteInfo) {
+        siteInfoDao.updateById(siteInfo);
+        return Map.of("id", siteInfo.getId());
+    }
+
+}

+ 11 - 11
src/main/java/com/backendsys/modules/common/config/security/CorsConfig.java

@@ -25,18 +25,18 @@
 ////        registry.addInterceptor(translationInterceptor).addPathPatterns("/**");
 ////    }
 //
-//    @Autowired
-//    private PreAuthorizeInterceptor preAuthorizeInterceptor;
+////    @Autowired
+////    private PreAuthorizeInterceptor preAuthorizeInterceptor;
 //
-//    @Override
-//    public void addInterceptors(InterceptorRegistry registry) {
-//        registry.addInterceptor(preAuthorizeInterceptor)
-//            .addPathPatterns("/**")
-//            .excludePathPatterns("/swagger-ui/**")
-//            .excludePathPatterns("/images/**")
-//            .excludePathPatterns("/favicon.ico")
-//        ;
-//    }
+////    @Override
+////    public void addInterceptors(InterceptorRegistry registry) {
+////        registry.addInterceptor(preAuthorizeInterceptor)
+////            .addPathPatterns("/**")
+////            .excludePathPatterns("/swagger-ui/**")
+////            .excludePathPatterns("/images/**")
+////            .excludePathPatterns("/favicon.ico")
+////        ;
+////    }
 //
 //    @Override
 //    public void addCorsMappings(CorsRegistry registry) {

+ 10 - 0
src/main/java/com/backendsys/modules/common/utils/views/MvcRequest.java

@@ -0,0 +1,10 @@
+package com.backendsys.modules.common.utils.views;
+
+import lombok.Data;
+
+@Data
+public class MvcRequest {
+    private String uri;
+    private String queryString;
+    private Long timestamp;
+}

+ 43 - 0
src/main/java/com/backendsys/modules/common/utils/views/MvcUtil.java

@@ -0,0 +1,43 @@
+package com.backendsys.modules.common.utils.views;
+
+
+import cn.hutool.core.date.DateUtil;
+import jakarta.servlet.http.HttpServletRequest;
+import org.springframework.ui.Model;
+
+import java.util.List;
+import java.util.Map;
+
+public class MvcUtil {
+
+    // 初始化 Request
+    public static MvcRequest getRequestVO (HttpServletRequest request) {
+        MvcRequest req = new MvcRequest();
+        req.setUri(request.getRequestURI());
+        req.setQueryString(request.getQueryString());
+        req.setTimestamp(DateUtil.current());
+        return req;
+    }
+
+//    // 初始化公共事件
+//    public static void initResponse (Model model, HttpServletRequest request,
+////         CmsSiteInfoService cmsSiteInfoService, CmsNavigationService cmsNavigationService) {
+////        // -- Request (uri, timestamp) ---------------------------
+////        model.addAttribute(getRequestVO(request));
+////        // -- Language -------------------------------------------
+////        String lang = CookieUtil.getCookie("lang", request);
+////        lang = (lang != null ? lang : (String) request.getAttribute("lang"));
+////        model.addAttribute("lang", lang);
+////
+////        // -- 初始化 网站信息 ---------------------------------------
+////        model.addAttribute("siteInfo", cmsSiteInfoService.querySiteInfo());
+////
+////        // -- 初始化 导航信息 ---------------------------------------
+////        CmsNavigationDTO cmsNavigationDTO = new CmsNavigationDTO();
+////        cmsNavigationDTO.setLang((String) model.getAttribute("lang"));
+////        List<Map<String, Object>> navigation = cmsNavigationService.queryNavigationPublic(cmsNavigationDTO);
+////        List<Map<String, Object>> navigationTree = TreeUtil.buildTree(navigation);
+////        model.addAttribute("navigation", navigationTree);
+//    }
+
+}

+ 97 - 0
src/main/resources/__templates/__article.html

@@ -0,0 +1,97 @@
+<div class="hjcl-layout-container" th:fragment="body">
+
+  <!-- 内页 幻灯片区域 -->
+  <div th:replace="~{components/sub-banner::sub-banner}"></div>
+
+  <!-- 内容 -->
+  <div class="sub-section-main">
+    <div class="wrapper">
+
+      <!-- 主要位置 -->
+      <div class="sub-section-container">
+        <div class="sub-section-container-title" th:text="${parameters.category_name}"></div>
+        <div class="sub-section-container-content">
+
+          <!-- 搜索框 -->
+          <div class="sub-search">
+            <div th:replace="~{components/search-input::search-input}"></div>
+          </div>
+
+          <div class="article-list" th:classappend="${isBrand ? 'column' : ''}">
+            <div class="article-item" th:each="item, itemStat : ${article.list}">
+              <a class="article-thumb" th:href="@{'/articleDetail/' + ${item.id}}"><img th:src="${item.thumb}" /></a>
+              <div class="article-info">
+                <a class="article-info-title" th:href="@{'/articleDetail/' + ${item.id}}">
+                  <span th:text="${item.title}"></span>
+                  <span th:if="${item.is_top == 1}" th:text="@{'[' + #{settop} + ']'}"></span>
+                </a>
+                <div class="article-info-description" th:text="${item.description}"></div>
+                <div class="article-info-bottom">
+                  <div class="article-info-time" th:text="${item.create_time}"></div>
+                  <a class="article-info-btn" th:href="@{'/articleDetail/' + ${item.id}}" th:text="#{viewdetail}"></a>
+                </div>
+              </div>
+            </div>
+          </div>
+          <div id="pagination-bar"></div>
+
+        </div>
+      </div>
+
+      <!-- 侧边 -->
+      <div class="sub-section-sider">
+        <div class="sub-section-sider-title" th:text="#{category}"></div>
+
+        <div class="sub-section-sider-content">
+          <div class="article-category horizontal">
+            <ul id="category-bar">
+<!--              <li class="mb-4"><a href="javascript:;" th:classappend="${parameters.category_id == null ? 'font-bold text-blue' : ''}">全部</a></li>-->
+              <li th:each="item, itemStat : ${articleCategory}" th:if="${item.is_brand == 1}">
+                <a href="javascript:;" th:text="${lang} == 'zh' ? ${item.category_name} : ${item.category_name_en}" th:data-category-id="${item.article_category_id}"
+                   th:classappend="(${item.article_category_id} == ${parameters.category_id} ? 'active' : '')"></a>
+              </li>
+            </ul>
+          </div>
+        </div>
+        <div class="sub-section-sider-content mt-2">
+          <p th:text="#{sub.sider.welcome}"></p>
+          <p th:text="@{#{sub.sider.wechat} + ' cpnana8 / anywayto'}"></p>
+        </div>
+      </div>
+
+    </div>
+  </div>
+
+</div>
+<script th:inline="javascript">
+  var lang = $.cookie('lang')
+
+  // [Click] 分类
+    $('#category-bar > li > a').on('click', function(){
+        var category_id = $(this).attr('data-category-id')
+        if (category_id) {
+            window.location.href = QueryString.updateParams({ category_id: parseInt(category_id) })
+        } else {
+            window.location.href = window.location.href.split('?')[0];
+        }
+    })
+    // [Click] 分页
+  console.log(lang)
+    layui.use('laypage', function(){
+        var laypage = layui.laypage
+        laypage.render({
+            elem: 'pagination-bar', theme: '#333e46',
+            prev: (lang == 'zh' ? '上一页' : 'Prev'),
+            next: (lang == 'zh' ? '下一页' : 'Next'),
+            count: [[${article.total}]], curr: [[${article.page_num}]], limit: [[${article.page_size}]],
+            jump: function(obj, first) {
+                // console.log(obj)
+                // 首次不执行
+                if (!first) {
+                  //do something
+                  window.location.href = QueryString.updateParams({ page_num: obj.curr, page_size: obj.limit })
+                }
+            }
+        })
+    })
+</script>

+ 24 - 0
src/main/resources/__templates/__layout/head.html

@@ -0,0 +1,24 @@
+<head th:fragment="header">
+  <meta charset="UTF-8" />
+  <meta http-equiv="pragma" content="no-cache" />
+  <meta http-equiv="expires" content="0" />
+  <meta http-equiv="cache-control" content="no-cache, no-store, must-revalidate" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
+  <title th:text="${title} + ' - ' + ${siteInfo.name}"></title>
+  <meta name="keywords" th:content="${siteInfo.meta_keyword}" />
+  <meta name="description" th:content="${siteInfo.meta_description}" />
+  <link rel="shortcut icon" th:href="@{'/images/favicon.ico'}" type="image/x-icon"/>
+  <link rel="stylesheet" th:href="@{'/css/reset.css'}">
+
+  <link rel="stylesheet" th:href="@{'/js/plugins/layui/css/layui.css'}">
+  <script th:src="@{'/js/plugins/layui/layui.js'}"></script>
+
+  <link rel="stylesheet" th:href="@{'/js/plugins/swiper/swiper.min.css'}">
+  <script th:src="@{'/js/plugins/swiper/swiper.min.js'}"></script>
+
+  <link rel="stylesheet" th:href="@{'/css/public.css?v=' + ${requestVO.timestamp}}">
+  <link rel="stylesheet" th:href="@{'/css/default.css?v=' + ${requestVO.timestamp}}">
+  <script th:src="@{'/js/plugins/jquery.min.js'}"></script>
+  <script th:src="@{'/js/plugins/jquery.cookie.min.js'}"></script>
+  <script th:src="@{'/js/default.js?v=' + ${requestVO.timestamp}}"></script>
+</head>

+ 73 - 0
src/main/resources/__templates/__layout/layout-footer.html

@@ -0,0 +1,73 @@
+<div th:fragment="layout-footer">
+
+  <div class="footer-menutabs">
+    <a href="/" class="footer-menutabs-item"
+       th:classappend="${(requestVO.uri == '/' ? 'active' : '')}">
+       <img src="/images/icon-watch.svg" />
+      <span th:text="#{footer.menu.home}"></span>
+    </a>
+    <a href="/article?category_id=1" class="footer-menutabs-item"
+       th:classappend="${(requestVO.uri + '?' + requestVO.queryString) == '/article?category_id=1' ? 'active' : ''}">
+      <img src="/images/icon-product.svg" />
+      <span th:text="#{footer.menu.product}"></span>
+    </a>
+    <a href="/article?category_id=42" class="footer-menutabs-item"
+       th:classappend="${(requestVO.uri + '?' + requestVO.queryString) == '/article?category_id=42' ? 'active' : ''}">
+      <img src="/images/icon-video.svg" />
+      <span th:text="#{footer.menu.video}"></span>
+    </a>
+    <a href="/article?category_id=43" class="footer-menutabs-item"
+       th:classappend="${(requestVO.uri + '?' + requestVO.queryString) == '/article?category_id=43' ? 'active' : ''}">
+      <img src="/images/icon-ce.svg" />
+      <span th:text="#{footer.menu.ce}"></span>
+    </a>
+
+    <!-- 微信联系 -->
+    <a href="javascript:;" class="footer-menutabs-item" id="menuWechat"
+       th:attr="data-text1=#{footer.menu.wechatinfo.text1}, data-text2=#{footer.menu.wechatinfo.text2}"
+      >
+      <img src="/images/icon-wechat.svg" />
+      <span th:text="#{footer.menu.wechat}"></span>
+    </a>
+    <script>
+      // [Click] 点击 微信联系
+      $('#menuWechat').on('click', function() {
+        var text1 = $(this).attr('data-text1')
+        var text2 = $(this).attr('data-text2')
+        layer.open({
+          title: false, shadeClose: true, closeBtn: false,
+          content: '<div class="menu-wechat-dialog-content">' +
+              '<img src="/images/qrcode-wechat.jpg"/><div>' + text1 + '<br/>' + text2 + ':cpnana8</div>' +
+              '</div>',
+          btn: []
+        })
+      })
+    </script>
+    <style>
+      .menu-wechat-dialog-content > img { display: block; width: 160px; height: 160px; margin: 10px auto; }
+      .menu-wechat-dialog-content > div { font-size: 14px; text-align: center; line-height: 18px; }
+    </style>
+
+  </div>
+
+
+  <div class="hjcl-layout-footer flex items-center justify-center">
+    <div class="wrapper">
+
+      <ul class="footer-nav flex items-center justify-center mb-2">
+        <li th:each="nav, iterStat : ${navigation}" class="mx-2">
+          <a th:href="${nav.link}" th:class="${'link underline-hover underline-offset-4 '}">
+            <span th:text="${nav.navigation_name}"></span>
+          </a>
+          <span class="ml-3" th:if="${iterStat.index != navigation.size - 1}">|</span>
+        </li>
+      </ul>
+
+      <div class="footer-copyright flex items-center justify-center">
+        <span class="mx-1" th:utext="${siteInfo.copyright}"></span>
+        <span class="mx-1" th:utext="${siteInfo.icp}"></span>
+      </div>
+
+    </div>
+  </div>
+</div>

+ 61 - 0
src/main/resources/__templates/__layout/layout-header.html

@@ -0,0 +1,61 @@
+<div th:fragment="layout-header" class="hjcl-layout-header">
+
+  <div class="wrapper">
+
+    <div class="nav-menu" id="navMenu"></div>
+    <div class="nav-right-bar">
+      <div th:replace="~{components/language::language}"></div>
+    </div>
+
+    <!-- 导航 -->
+    <ul class="nav" id="nav">
+
+      <li class="first-nav-item" th:text="#{sub.sider.title.nav}"></li>
+
+      <li th:each="nav, iterStat : ${navigation}"
+          th:class="${(iterStat.index + 1 == (navigation.size + 1) / 2) ? 'middle-l' : (iterStat.index == (navigation.size + 1) / 2) ? 'middle-r' : ''}">
+        <div class="flex justify-between">
+          <a th:href="${nav.link}"
+             th:class="${'link underline-hover underline-offset-4 ' + (requestVO.uri == nav.link ? 'active' : '') + (nav.is_blank == 1 ? 'underline' : '')}">
+            <span th:text="${nav.navigation_name}"></span>
+          </a>
+          <span th:if="${nav.children.size > 0}" class="nav-more" id="navMore">+</span>
+        </div>
+        <!-- 子级导航 -->
+        <div th:if="${nav.children.size > 0}" class="navSub">
+          <div th:each="navChild : ${nav.children}">
+            <a th:href="${navChild.link}" th:text="${navChild.navigation_name}"></a>
+          </div>
+        </div>
+
+      </li>
+    </ul>
+    <div class="nav-mask" id="navMask"></div>
+    <script>
+      // [Click] 点击显示左侧 (或顶部) 导航
+      $('#navMenu').on('click', function() {
+          $(this).toggleClass('active')
+          $('#nav, #navMask').toggleClass('active')
+      })
+      // [Click] 导航 遮罩层
+      $('#navMask').on('click', function() {
+          $('#nav, #navMask').toggleClass('active')
+      })
+      // [Click] 点击子级导航
+      $('#navMore').on('click', function() {
+          // 切换文本内容
+          $(this).text(function(index, currentText) {
+              return currentText === '+' ? '-' : '+'
+          })
+          // 显示/隐藏菜单
+          $(this).parent().next('.navSub').toggleClass('active');
+      })
+    </script>
+
+    <!-- Logo -->
+    <a href="/" class="header-logo-link">
+      <img class="header-logo" th:src="@{/images/logo.png}" />
+    </a>
+
+  </div>
+</div>

+ 8 - 0
src/main/resources/__templates/__layout/layout-top.html

@@ -0,0 +1,8 @@
+<div th:fragment="layout-top" class="hjcl-layout-top">
+  <div class="wrapper">
+    <div class="text-xs"><span th:text="#{top.welcome}"></span>:cpnana8 / anywayto</div>
+    <div class="text-xs">
+      <div th:replace="~{components/language::language}"></div>
+    </div>
+  </div>
+</div>

+ 10 - 0
src/main/resources/__templates/__layout/layout.html

@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html lang="en" xmlns:th="http://www.thymeleaf.org">
+<head th:replace="~{layout/head::head}"></head>
+<body>
+<div th:replace="~{layout/layout-top::layout-top}"></div>
+<div th:replace="~{layout/layout-header::layout-header}"></div>
+<th:block th:replace="~{${layout}}" />
+<div th:replace="~{layout/layout-footer::layout-footer}"></div>
+</body>
+</html>

+ 3 - 0
src/main/resources/__templates/article.html

@@ -0,0 +1,3 @@
+<div class="hjcl-layout-container" th:fragment="body">
+  article
+</div>

+ 68 - 0
src/main/resources/__templates/articleDetail.html

@@ -0,0 +1,68 @@
+<div class="hjcl-layout-container" th:fragment="body">
+
+  <!-- 内页 幻灯片区域 -->
+  <div th:replace="~{components/sub-banner::sub-banner}"></div>
+
+  <!-- 内容 -->
+  <div class="sub-section-main">
+    <div class="wrapper">
+      <div class="sub-section-container">
+
+        <div class="article-detail">
+          <div class="sub-section-container-title">
+            <div class="article-detail-title" th:text="${articleDetail.title}"></div>
+            <div class="article-detail-subtitle">
+                <div th:text="${articleDetail.create_time}"></div>
+                <a class="back" href="javascript:history.back();" th:text="#{back}"></a>
+            </div>
+          </div>
+          <div class="sub-section-container-content bg-white" style="padding: 20px; box-sizing: border-box">
+            <div class="sub-section-container-description" th:text="${articleDetail.description}"></div>
+            <div class="content-detail" >
+
+              <div th:if="${articleDetail.video != null && articleDetail.video != ''}" class="article-video-bar">
+                <video class="article-video" th:src="${articleDetail.video}" controls></video>
+              </div>
+
+              <div th:utext="${articleDetail.content}"></div>
+
+            </div>
+          </div>
+        </div>
+
+      </div>
+
+      <!-- 侧边 -->
+      <div class="sub-section-sider">
+        <div class="sub-section-sider-title" th:text="#{category}"></div>
+        <div class="sub-section-sider-content">
+          <div class="article-category horizontal">
+            <ul id="category-bar">
+<!--              <li class="mb-4"><a href="javascript:;">全部</a></li>-->
+              <li th:each="item, itemStat : ${articleCategory}" th:if="${item.is_brand == 1}">
+                <a href="javascript:;" th:text="${lang} == 'zh' ? ${item.category_name} : ${item.category_name_en}" th:data-category-id="${item.article_category_id}"></a>
+              </li>
+            </ul>
+          </div>
+        </div>
+        <div class="sub-section-sider-content mt-2">
+            <p th:text="#{sub.sider.welcome}"></p>
+            <p th:text="@{#{sub.sider.wechat} + ' cpnana8 / anywayto'}"></p>
+        </div>
+      </div>
+      <script th:inline="javascript">
+          // [Click] 分类
+          $('#category-bar > li > a').on('click', function(){
+              var category_id = $(this).attr('data-category-id')
+              if (category_id) {
+                  window.location.href = '/article?category_id=' + parseInt(category_id)
+              } else {
+                  window.location.href = '/article';
+              }
+          })
+      </script>
+
+    </div>
+  </div>
+
+</div>

+ 20 - 0
src/main/resources/__templates/components/language.html

@@ -0,0 +1,20 @@
+<div th:fragment="language">
+
+  <ul class="flex items-center">
+    <li class="ml-4">
+      <a href="javascript:;" onclick="setLangAndRefresh('zh');"
+         th:classappend="${lang} == 'zh' ? 'font-bold' : ''">中文</a>
+    </li>
+    <li class="ml-4">
+      <a href="javascript:;" onclick="setLangAndRefresh('en');"
+         th:classappend="${lang} == 'en' ? 'font-bold' : ''">English</a>
+    </li>
+  </ul>
+  <script>
+      function setLangAndRefresh(lang) {
+          document.cookie = "lang=" + lang + ";max-age=2592000;path=/"
+          location.reload()
+      }
+  </script>
+
+</div>

+ 22 - 0
src/main/resources/__templates/components/search-input.html

@@ -0,0 +1,22 @@
+<div th:fragment="search-input">
+
+  <div class="index-search">
+    <input class="index-search-input" th:value="${parameters != null ? parameters.title : ''}" id="searchInput" type="text"
+       th:placeholder="#{search.input.placeholder}" maxlength="25">
+    <a href="javascript:;" id="searchBtn" class="index-search-btn"><i class="icon-search-white"></i></a>
+  </div>
+  <script>
+    $('#searchBtn').on('click', function() {
+        var val = $('#searchInput').val()
+        if (val) {
+          window.location.href = '/article?title=' + val
+        } else {
+          window.location.href = '/article'
+        }
+    })
+    $('#searchInput').on('keydown', function(e) {
+        if (e.keyCode === 13) $('#searchBtn').click()
+    })
+  </script>
+
+</div>

+ 2 - 0
src/main/resources/__templates/components/sub-banner.html

@@ -0,0 +1,2 @@
+<div th:fragment="sub-banner" class="sub-banner">
+</div>

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 16 - 0
src/main/resources/__templates/error.html


+ 88 - 0
src/main/resources/__templates/index.html

@@ -0,0 +1,88 @@
+<div class="hjcl-layout-container" th:fragment="body">
+
+
+  <div class="index-banner">
+    <!-- 首页 幻灯片 -->
+    <div class="swiper-container">
+      <div class="swiper-wrapper">
+        <!-- style="background-color: transparent" -->
+        <div th:each="item, itemStat : ${bannerList}" class="swiper-slide">
+          <a th:href="${item.link}">
+            <img th:src="${item.image}" class="banner-img" />
+          </a>
+        </div>
+      </div>
+      <div class="swiper-pagination"></div>
+    </div>
+    <script>
+        var swiper = new Swiper('.swiper-container', {
+            pagination: '.swiper-pagination',
+            paginationClickable: true,
+            loop: true
+        });
+    </script>
+    <!-- 搜索框 -->
+    <div class="index-search-bar">
+      <div th:replace="~{components/search-input::search-input}"></div>
+    </div>
+  </div>
+
+
+  <div class="index-section index-section-1">
+
+    <div class="wrapper">
+      <div class="wrapper">
+        <div class="index-section-hd">
+          <div class="index-section-title">
+            <div class="index-section-maintitle" th:text="#{index.section1.title}"></div>
+          </div>
+          <div class="index-section-more"><a href="/article?category_id=1"><span th:text="#{more}"></span>+</a></div>
+        </div>
+      </div>
+
+      <div class="index-article-list">
+        <div class="index-article-item" th:each="item, itemStat : ${articleList1.list}">
+          <a th:href="@{'/articleDetail/' + ${item.id}}">
+            <img class="article-item-thumb" th:src="${item.thumb}" />
+            <div class="article-item-title" th:text="${item.title}"></div>
+          </a>
+        </div>
+      </div>
+
+    </div>
+
+  </div>
+
+  <div class="index-subbanner w-full text-center" style="background-color: rgba(1, 6, 10, 1);">
+    <img class="wrapper" th:src="@{/images/index-section-1.jpg}" />
+  </div>
+
+
+  <div class="index-section index-section-2">
+    <div class="wrapper">
+      <div class="index-section-hd">
+        <div class="index-section-title">
+          <div class="index-section-maintitle" th:text="#{index.section2.title}"></div>
+        </div>
+        <div class="index-section-more"><a href="/article?category_id=2"><span th:text="#{more}"></span>+</a></div>
+      </div>
+
+      <div>
+        <div class="index-article-list">
+          <div class="index-article-item" th:each="item, itemStat : ${articleList2.list}">
+            <a th:href="@{'/articleDetail/' + ${item.id}}">
+              <img class="article-item-thumb" th:src="${item.thumb}" />
+              <div class="article-item-title" th:text="${item.title}"></div>
+            </a>
+          </div>
+        </div>
+      </div>
+
+    </div>
+  </div>
+
+  <div class="index-subbanner w-full text-center" style="background-color: rgba(38, 47, 54, 1);">
+    <img class="wrapper" th:src="@{/images/index-section-2.jpg}" />
+  </div>
+
+</div>

+ 8 - 0
src/main/resources/__templates/layout/head.html

@@ -0,0 +1,8 @@
+<head th:fragment="header">
+  <meta charset="UTF-8" />
+  <meta http-equiv="pragma" content="no-cache" />
+  <meta http-equiv="expires" content="0" />
+  <meta http-equiv="cache-control" content="no-cache, no-store, must-revalidate" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
+  <link rel="shortcut icon" th:href="@{'/images/favicon.ico'}" type="image/x-icon"/>
+</head>

+ 3 - 0
src/main/resources/__templates/layout/layout-footer.html

@@ -0,0 +1,3 @@
+<div th:fragment="layout-footer">
+  footer
+</div>

+ 3 - 0
src/main/resources/__templates/layout/layout-header.html

@@ -0,0 +1,3 @@
+<div th:fragment="layout-header" class="hjcl-layout-header">
+  header
+</div>

+ 3 - 0
src/main/resources/__templates/layout/layout-top.html

@@ -0,0 +1,3 @@
+<div th:fragment="layout-top" class="hjcl-layout-top">
+  top
+</div>

+ 10 - 0
src/main/resources/__templates/layout/layout.html

@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html lang="en" xmlns:th="http://www.thymeleaf.org">
+<head th:replace="~{layout/head::head}"></head>
+<body>
+<div th:replace="~{layout/layout-top::layout-top}"></div>
+<div th:replace="~{layout/layout-header::layout-header}"></div>
+<th:block th:replace="~{${layout}}" />
+<div th:replace="~{layout/layout-footer::layout-footer}"></div>
+</body>
+</html>

+ 31 - 0
src/main/resources/__templates/page.html

@@ -0,0 +1,31 @@
+<div class="hjcl-layout-container" th:fragment="body">
+
+  <!-- 内页 幻灯片区域 -->
+  <div th:replace="~{components/sub-banner::sub-banner}"></div>
+
+  <!-- 内容 -->
+  <div class="sub-section-main">
+    <div class="wrapper">
+
+      <!-- 主要位置 -->
+      <div class="sub-section-container">
+        <div class="sub-section-container-title" th:text="${pageDetail.title}"></div>
+        <div class="sub-section-container-content">
+          <div class="bg-white" style="padding: 30px; box-sizing: border-box"
+             th:utext="${pageDetail.content}"></div>
+        </div>
+      </div>
+
+      <!-- 侧边 -->
+      <div class="sub-section-sider">
+        <div class="sub-section-sider-title" th:text="#{sub.sider.title.nav}"></div>
+        <div class="sub-section-sider-content">
+          <p th:text="#{sub.sider.welcome}"></p>
+          <p th:text="@{#{sub.sider.wechat} + ' cpnana8 / anywayto'}"></p>
+        </div>
+      </div>
+
+    </div>
+  </div>
+
+</div>

+ 1 - 86
src/main/resources/templates/index.html

@@ -1,88 +1,3 @@
 <div class="hjcl-layout-container" th:fragment="body">
-
-
-  <div class="index-banner">
-    <!-- 首页 幻灯片 -->
-    <div class="swiper-container">
-      <div class="swiper-wrapper">
-        <!-- style="background-color: transparent" -->
-        <div th:each="item, itemStat : ${bannerList}" class="swiper-slide">
-          <a th:href="${item.link}">
-            <img th:src="${item.image}" class="banner-img" />
-          </a>
-        </div>
-      </div>
-      <div class="swiper-pagination"></div>
-    </div>
-    <script>
-        var swiper = new Swiper('.swiper-container', {
-            pagination: '.swiper-pagination',
-            paginationClickable: true,
-            loop: true
-        });
-    </script>
-    <!-- 搜索框 -->
-    <div class="index-search-bar">
-      <div th:replace="~{components/search-input::search-input}"></div>
-    </div>
-  </div>
-
-
-  <div class="index-section index-section-1">
-
-    <div class="wrapper">
-      <div class="wrapper">
-        <div class="index-section-hd">
-          <div class="index-section-title">
-            <div class="index-section-maintitle" th:text="#{index.section1.title}"></div>
-          </div>
-          <div class="index-section-more"><a href="/article?category_id=1"><span th:text="#{more}"></span>+</a></div>
-        </div>
-      </div>
-
-      <div class="index-article-list">
-        <div class="index-article-item" th:each="item, itemStat : ${articleList1.list}">
-          <a th:href="@{'/articleDetail/' + ${item.id}}">
-            <img class="article-item-thumb" th:src="${item.thumb}" />
-            <div class="article-item-title" th:text="${item.title}"></div>
-          </a>
-        </div>
-      </div>
-
-    </div>
-
-  </div>
-
-  <div class="index-subbanner w-full text-center" style="background-color: rgba(1, 6, 10, 1);">
-    <img class="wrapper" th:src="@{/images/index-section-1.jpg}" />
-  </div>
-
-
-  <div class="index-section index-section-2">
-    <div class="wrapper">
-      <div class="index-section-hd">
-        <div class="index-section-title">
-          <div class="index-section-maintitle" th:text="#{index.section2.title}"></div>
-        </div>
-        <div class="index-section-more"><a href="/article?category_id=2"><span th:text="#{more}"></span>+</a></div>
-      </div>
-
-      <div>
-        <div class="index-article-list">
-          <div class="index-article-item" th:each="item, itemStat : ${articleList2.list}">
-            <a th:href="@{'/articleDetail/' + ${item.id}}">
-              <img class="article-item-thumb" th:src="${item.thumb}" />
-              <div class="article-item-title" th:text="${item.title}"></div>
-            </a>
-          </div>
-        </div>
-      </div>
-
-    </div>
-  </div>
-
-  <div class="index-subbanner w-full text-center" style="background-color: rgba(38, 47, 54, 1);">
-    <img class="wrapper" th:src="@{/images/index-section-2.jpg}" />
-  </div>
-
+  index
 </div>

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä