From ad2fc69d87a8ba4d2f4b248e571b7207bdd9261e Mon Sep 17 00:00:00 2001
From: xiangpei <xiangpei@timesnew.cn>
Date: 星期一, 19 五月 2025 18:05:17 +0800
Subject: [PATCH] 集成腾讯云cos、小程序视频发布功能

---
 framework/src/main/java/cn/lili/modules/lmk/domain/entity/LmkFile.java               |   38 +
 framework/src/main/java/cn/lili/modules/lmk/domain/form/FileInfoForm.java            |   31 
 framework/src/main/java/cn/lili/modules/lmk/domain/form/VideoForm.java               |   64 +
 framework/src/main/java/cn/lili/cos/CosSTS.java                                      |   40 +
 framework/src/main/java/cn/lili/modules/lmk/domain/entity/VideoTagRef.java           |   31 
 framework/src/main/java/cn/lili/modules/lmk/domain/query/WxVideoTagQuery.java        |   25 
 framework/src/main/java/cn/lili/modules/lmk/domain/vo/VideoVO.java                   |   91 ++
 framework/src/main/java/cn/lili/utils/COSUtil.java                                   |  285 +++++++
 buyer-api/src/main/java/cn/lili/controller/lmk/VideoController.java                  |   77 ++
 framework/src/main/java/cn/lili/modules/lmk/service/impl/VideoServiceImpl.java       |  171 ++++
 pom.xml                                                                              |    3 
 framework/src/main/java/cn/lili/modules/lmk/domain/query/VideoQuery.java             |   22 
 framework/src/main/resources/mapper/lmk/VideoTagRefMapper.xml                        |   15 
 framework/src/main/java/cn/lili/cos/COSConfigProperty.java                           |  105 ++
 framework/src/main/java/cn/lili/modules/lmk/domain/entity/Video.java                 |   83 ++
 framework/src/main/resources/mapper/lmk/VideoMapper.xml                              |   80 ++
 framework/src/main/java/cn/lili/modules/lmk/service/LmkFileService.java              |   83 ++
 framework/src/main/java/cn/lili/modules/lmk/domain/entity/VideoTag.java              |    3 
 manager-api/src/main/java/cn/lili/controller/lmk/VideoController.java                |   76 ++
 framework/src/main/java/cn/lili/modules/lmk/service/VideoTagService.java             |    9 
 framework/src/main/java/cn/lili/utils/FileUtil.java                                  |   89 ++
 framework/src/main/java/cn/lili/modules/lmk/service/VideoService.java                |   73 +
 buyer-api/src/main/java/cn/lili/controller/lmk/VideoTagController.java               |   40 +
 framework/src/main/java/cn/lili/modules/lmk/mapper/VideoMapper.java                  |   34 
 framework/src/main/java/cn/lili/modules/lmk/service/impl/VideoTagRefServiceImpl.java |   23 
 framework/pom.xml                                                                    |   16 
 framework/src/main/java/cn/lili/modules/lmk/mapper/VideoTagRefMapper.java            |   17 
 framework/src/main/java/cn/lili/common/exception/FileFormatNotSupport.java           |   32 
 buyer-api/src/test/java/cn/lili/buyer/test/cart/LmkFileTest.java                     |    2 
 config/application.yml                                                               |   28 
 framework/src/main/java/cn/lili/modules/lmk/mapper/LmkFileMapper.java                |   26 
 framework/src/main/java/cn/lili/modules/lmk/domain/form/WxVideoTagForm.java          |   30 
 framework/src/main/java/cn/lili/modules/lmk/service/impl/LmkFileServiceImpl.java     |   93 ++
 framework/src/main/java/cn/lili/modules/lmk/enums/general/VideoStatusEnum.java       |   48 +
 framework/src/main/resources/mapper/lmk/VideoTagMapper.xml                           |    3 
 framework/src/main/java/cn/lili/modules/lmk/enums/general/FileTypeEnum.java          |   54 +
 framework/src/main/java/cn/lili/modules/lmk/service/VideoTagRefService.java          |   15 
 framework/src/main/java/cn/lili/common/security/context/UserContext.java             |   14 
 framework/src/main/resources/mapper/lmk/LmkFileMapper.xml                            |   35 
 common-api/src/main/java/cn/lili/controller/lmk/LmkFileController.java               |  112 ++
 framework/src/main/java/cn/lili/modules/lmk/service/impl/VideoTagServiceImpl.java    |   28 
 framework/src/main/java/cn/lili/common/exception/BaseException.java                  |   35 
 framework/src/main/java/cn/lili/modules/lmk/domain/vo/LmkFileVO.java                 |   49 +
 43 files changed, 2,225 insertions(+), 3 deletions(-)

diff --git a/buyer-api/src/main/java/cn/lili/controller/lmk/VideoController.java b/buyer-api/src/main/java/cn/lili/controller/lmk/VideoController.java
new file mode 100644
index 0000000..7d66e4f
--- /dev/null
+++ b/buyer-api/src/main/java/cn/lili/controller/lmk/VideoController.java
@@ -0,0 +1,77 @@
+package cn.lili.controller.lmk;
+
+import cn.lili.group.Update;
+import cn.lili.group.Add;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import lombok.RequiredArgsConstructor;
+import java.util.List;
+import org.springframework.validation.annotation.Validated;
+import javax.validation.constraints.NotEmpty;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import cn.lili.modules.lmk.service.VideoService;
+import cn.lili.base.Result;
+import cn.lili.modules.lmk.domain.form.VideoForm;
+import cn.lili.modules.lmk.domain.query.VideoQuery;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * 瑙嗛鍐呭 鍓嶇鎺у埗鍣�
+ *
+ * @author xp
+ * @since 2025-05-16
+ */
+@Validated
+@RequiredArgsConstructor
+@Api(value = "瑙嗛鍐呭", tags = "瑙嗛鍐呭绠$悊")
+@RestController
+@RequestMapping("/buyer/lmk/video")
+public class VideoController {
+
+    private final VideoService videoService;
+
+    @PostMapping("/publish")
+    @ApiOperation(value = "鍙戝竷瑙嗛", notes = "鍙戝竷瑙嗛")
+    public Result publish(@RequestBody @Validated({Add.class}) VideoForm form) {
+        return videoService.publish(form);
+    }
+
+    @PutMapping
+    @ApiOperation(value = "淇敼", notes = "淇敼")
+    public Result update(@RequestBody @Validated(Update.class) VideoForm form) {
+        return videoService.update(form);
+    }
+
+    @DeleteMapping("/{id}")
+    @ApiOperation(value = "ID鍒犻櫎", notes = "ID鍒犻櫎")
+    public Result removeById(@PathVariable("id") String id) {
+        return videoService.removeById(id);
+    }
+
+    @DeleteMapping("/batch")
+    @ApiOperation(value = "鎵归噺鍒犻櫎", notes = "鎵归噺鍒犻櫎")
+    public Result remove(@RequestBody @NotEmpty(message = "璇烽�夋嫨鏁版嵁") List<String> ids) {
+        return videoService.remove(ids);
+    }
+
+    @GetMapping("/page")
+    @ApiOperation(value = "鍒嗛〉", notes = "鍒嗛〉")
+    public Result page(VideoQuery query) {
+        return videoService.page(query);
+    }
+
+    @GetMapping("/{id}")
+    @ApiOperation(value = "璇︽儏", notes = "璇︽儏")
+    public Result detail(@PathVariable("id") Integer id) {
+        return videoService.detail(id);
+    }
+
+    @GetMapping("/list")
+    @ApiOperation(value = "鍒楄〃", notes = "鍒楄〃")
+    public Result list() {
+        return videoService.all();
+    }
+}
diff --git a/buyer-api/src/main/java/cn/lili/controller/lmk/VideoTagController.java b/buyer-api/src/main/java/cn/lili/controller/lmk/VideoTagController.java
new file mode 100644
index 0000000..3504538
--- /dev/null
+++ b/buyer-api/src/main/java/cn/lili/controller/lmk/VideoTagController.java
@@ -0,0 +1,40 @@
+package cn.lili.controller.lmk;
+
+import cn.lili.base.Result;
+import cn.lili.group.Update;
+import cn.lili.modules.lmk.domain.form.VideoForm;
+import cn.lili.modules.lmk.domain.query.VideoQuery;
+import cn.lili.modules.lmk.domain.query.WxVideoTagQuery;
+import cn.lili.modules.lmk.service.VideoService;
+import cn.lili.modules.lmk.service.VideoTagService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.constraints.NotEmpty;
+import java.util.List;
+
+/**
+ * 瑙嗛鏍囩 鍓嶇鎺у埗鍣�
+ *
+ * @author xp
+ * @since 2025-05-16
+ */
+@Validated
+@RequiredArgsConstructor
+@Api(value = "瑙嗛鏍囩", tags = "瑙嗛鏍囩")
+@RestController
+@RequestMapping("/buyer/lmk/video/tag")
+public class VideoTagController {
+
+    private final VideoTagService videoTagService;
+
+    @GetMapping("/recommend")
+    @ApiOperation(value = "鎺ㄨ崘鏍囩", notes = "鎺ㄨ崘鏍囩")
+    public Result recommend(WxVideoTagQuery query) {
+        return videoTagService.recommend(query);
+    }
+
+}
diff --git a/buyer-api/src/test/java/cn/lili/buyer/test/cart/FileTest.java b/buyer-api/src/test/java/cn/lili/buyer/test/cart/LmkFileTest.java
similarity index 98%
rename from buyer-api/src/test/java/cn/lili/buyer/test/cart/FileTest.java
rename to buyer-api/src/test/java/cn/lili/buyer/test/cart/LmkFileTest.java
index b7907bc..e36f97e 100644
--- a/buyer-api/src/test/java/cn/lili/buyer/test/cart/FileTest.java
+++ b/buyer-api/src/test/java/cn/lili/buyer/test/cart/LmkFileTest.java
@@ -23,7 +23,7 @@
 @Slf4j
 @ExtendWith(SpringExtension.class)
 @SpringBootTest
-class FileTest {
+class LmkFileTest {
 
 
     @Autowired
diff --git a/common-api/src/main/java/cn/lili/controller/lmk/LmkFileController.java b/common-api/src/main/java/cn/lili/controller/lmk/LmkFileController.java
new file mode 100644
index 0000000..5dc9c51
--- /dev/null
+++ b/common-api/src/main/java/cn/lili/controller/lmk/LmkFileController.java
@@ -0,0 +1,112 @@
+package cn.lili.controller.lmk;
+
+import cn.lili.base.Result;
+import cn.lili.modules.lmk.service.LmkFileService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.apache.ibatis.annotations.Delete;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ * 鏂囦欢淇℃伅 鍓嶇鎺у埗鍣�
+ *
+ * @author xp
+ * @since 2025-05-19
+ */
+@Validated
+@RequiredArgsConstructor
+@Api(value = "鏂囦欢绠$悊", tags = "鏂囦欢绠$悊")
+@RestController("lmkFileController")
+@RequestMapping("/common/lmk/file")
+public class LmkFileController {
+
+    private final LmkFileService lmkFileService;
+
+    /**
+     * 鍗曟枃浠朵笂浼�(杩斿洖鏈夎繃鏈熸椂闂寸殑閾炬帴)
+     *
+     * @param file
+     * @return
+     */
+    @PostMapping("/upload")
+    @ApiOperation(value = "鍗曟枃浠朵笂浼�(杩斿洖鏈夎繃鏈熸椂闂寸殑閾炬帴)")
+    public Result upload(@RequestPart("file") @NotNull MultipartFile file) {
+        return lmkFileService.uploadObject(file);
+    }
+
+
+    /**
+     * 澶氭枃浠朵笂浼�
+     *
+     * @param files
+     * @return
+     */
+    @PostMapping("/multi/upload")
+    @ApiOperation(value = "澶氭枃浠朵笂浼�(杩斿洖鏈夎繃鏈熸椂闂寸殑閾炬帴)")
+    public Result uploads(@RequestPart("files") @NotEmpty List<MultipartFile> files) {
+        return lmkFileService.uploadObjects(files);
+    }
+
+    /**
+     * 鍒犻櫎鏌愪釜鏂囦欢
+     *
+     * @param fileKey oss鏂囦欢鍚�
+     * @return
+     */
+    @Delete("/delete/{file_key}")
+    @ApiOperation(value = "鍒犻櫎鏌愪釜鏂囦欢")
+    public Result deleteObject(@PathVariable(value = "file_key") String fileKey) {
+        return lmkFileService.deleteObject(fileKey);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎鏂囦欢
+     *
+     * @param fileKeys
+     * @return
+     */
+    @Delete("/delete/files")
+    @ApiOperation(value = "鎵归噺鍒犻櫎鏂囦欢")
+    public Result deleteObjects(@RequestBody @NotEmpty List<String> fileKeys) {
+        return lmkFileService.deleteObjects(fileKeys);
+    }
+
+    /**
+     * 涓嬭浇鏂囦欢
+     *
+     * @param fileKey
+     * @return
+     */
+    @GetMapping("/download/{file_key}")
+    @ApiOperation(value = "涓嬭浇鏂囦欢")
+    public void downloadFile(@PathVariable(value = "file_key") String fileKey, HttpServletResponse response) {
+        lmkFileService.downloadObject(fileKey, response);
+    }
+
+    /**
+     * 棰勮鏂囦欢
+     *
+     * @param fileKey
+     * @return
+     */
+    @GetMapping("/preview/{file_key}")
+    @ApiOperation(value = "鑾峰彇鏂囦欢棰勮url(閾炬帴瀛樺湪鏃舵晥)")
+    public Result getPreviewUrl(@PathVariable(value = "file_key") String fileKey) {
+        return Result.ok().data(lmkFileService.getPreviewUrl(fileKey));
+    }
+
+
+    @GetMapping("/sts")
+    @ApiOperation(value = "鑾峰彇STS璁块棶浠ょ墝", notes = "鍓嶇鍋氱洿浼�")
+    public Result getSTSToken() {
+        return Result.ok().data(lmkFileService.getSTSToken());
+    }
+}
diff --git a/config/application.yml b/config/application.yml
index 80ffe59..d5c9fae 100644
--- a/config/application.yml
+++ b/config/application.yml
@@ -314,3 +314,31 @@
       port: 8891
       logpath: ./xxl-job/executor
       logretentiondays: 7
+
+# 鑵捐cos-sts閰嶇疆
+cos:
+  secretId: AKIDYyBCzb1FOPGx0fCXfdOwJVWM1TjqmW3N  # 鑵捐ARM鐢ㄦ埛鐨剆ecretId
+  secretKey: DD1b1LWVIvPlusAOYjnfKm150jO0NYWH  # 鑵捐ARM鐢ㄦ埛鐨剆ecretKey
+  durationSeconds: 1800  # STS涓存椂璁块棶鍑瘉鏈夋晥鏈燂紝鍗曚綅绉掞紝榛樿1800s锛屼富璐﹀彿鏈�闀�2灏忔椂锛屽瓙璐﹀彿(ARM鐢ㄦ埛)36灏忔椂
+  bucket: lmk-1308069279
+  region: ap-chengdu
+  urlExpireMinute: 360  # 棰勭鍚島rl鏈夋晥鏃堕棿(鍒嗛挓)
+  actions:  # sts鐨勬潈闄�
+    - cos:ListMultipartUploads
+    - cos:GetBucket
+    - cos:GetObject
+    - cos:GetObjectTagging
+    - cos:GetSymlink
+    - cos:HeadObject
+    - cos:ListParts
+    - cos:AbortMultipartUpload
+    - cos:AppendObject
+    - cos:CompleteMultipartUpload
+    - cos:InitiateMultipartUpload
+    - cos:PostObject
+    - cos:PutObject
+    - cos:UploadPart
+    - cos:DeleteObject
+    - cos:PutObjectTagging
+  resources: # 鑳芥搷浣滃摢浜涜祫婧�
+    - qcs::cos:ap-chengdu:uid/1308069279:lmk-1308069279/*
diff --git a/framework/pom.xml b/framework/pom.xml
index bfcd88a..3851799 100644
--- a/framework/pom.xml
+++ b/framework/pom.xml
@@ -15,6 +15,20 @@
     <packaging>jar</packaging>
 
     <dependencies>
+        <!-- 鑵捐cos瀵硅薄瀛樺偍鏈嶅姟 -->
+        <dependency>
+            <groupId>com.qcloud</groupId>
+            <artifactId>cos_api</artifactId>
+            <version>${tx-cos.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.qcloud</groupId>
+            <artifactId>cos-sts_api</artifactId>
+            <version>3.1.0</version>
+        </dependency>
+
+
+
         <dependency>
             <groupId>com.qiniu</groupId>
             <artifactId>qiniu-java-sdk</artifactId>
@@ -471,4 +485,4 @@
     </dependencies>
 
 
-</project>
\ No newline at end of file
+</project>
diff --git a/framework/src/main/java/cn/lili/common/exception/BaseException.java b/framework/src/main/java/cn/lili/common/exception/BaseException.java
new file mode 100644
index 0000000..7ddef4c
--- /dev/null
+++ b/framework/src/main/java/cn/lili/common/exception/BaseException.java
@@ -0,0 +1,35 @@
+package cn.lili.common.exception;
+
+/**
+ * 鍩虹闈炴鏌ュ紓甯�
+ * @author 29443
+ * @version 1.0
+ * @date 2022/4/25
+ */
+public class BaseException extends RuntimeException {
+
+    private String msg;
+
+    private Integer code;
+
+    public BaseException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+
+    public BaseException(String msg) {
+        super(msg);
+    }
+
+    public BaseException(String msg, Integer code) {
+        this.msg = msg;
+        this.code = code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public Integer getCode() {
+        return code;
+    }
+}
diff --git a/framework/src/main/java/cn/lili/common/exception/FileFormatNotSupport.java b/framework/src/main/java/cn/lili/common/exception/FileFormatNotSupport.java
new file mode 100644
index 0000000..5b1c87f
--- /dev/null
+++ b/framework/src/main/java/cn/lili/common/exception/FileFormatNotSupport.java
@@ -0,0 +1,32 @@
+package cn.lili.common.exception;
+
+/**
+ * @author 29443
+ * @version 1.0
+ * @date 2022/4/25
+ */
+public class FileFormatNotSupport extends BaseException {
+
+    private String suffix;
+
+    public FileFormatNotSupport(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+
+    public FileFormatNotSupport(String msg) {
+        super(msg);
+    }
+
+    public FileFormatNotSupport(String msg, String suffix) {
+        super(msg);
+        this.suffix = suffix;
+    }
+
+    public FileFormatNotSupport(String msg, Integer code) {
+        super(msg, code);
+    }
+
+    public String getSuffix() {
+        return suffix;
+    }
+}
diff --git a/framework/src/main/java/cn/lili/common/security/context/UserContext.java b/framework/src/main/java/cn/lili/common/security/context/UserContext.java
index d2770be..cf66baf 100644
--- a/framework/src/main/java/cn/lili/common/security/context/UserContext.java
+++ b/framework/src/main/java/cn/lili/common/security/context/UserContext.java
@@ -26,6 +26,20 @@
 public class UserContext {
 
     /**
+     * 鏍规嵁request鑾峰彇鐢ㄦ埛id
+     *
+     * @return 鎺堟潈鐢ㄦ埛
+     */
+    public static String getCurrentUserId() {
+        if (RequestContextHolder.getRequestAttributes() != null) {
+            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
+            String accessToken = request.getHeader(SecurityEnum.HEADER_TOKEN.getValue());
+            return getAuthUser(accessToken).getId();
+        }
+        return null;
+    }
+
+    /**
      * 鏍规嵁request鑾峰彇鐢ㄦ埛淇℃伅
      *
      * @return 鎺堟潈鐢ㄦ埛
diff --git a/framework/src/main/java/cn/lili/cos/COSConfigProperty.java b/framework/src/main/java/cn/lili/cos/COSConfigProperty.java
new file mode 100644
index 0000000..70c5f4f
--- /dev/null
+++ b/framework/src/main/java/cn/lili/cos/COSConfigProperty.java
@@ -0,0 +1,105 @@
+package cn.lili.cos;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.List;
+
+/**
+ * 璇诲彇閰嶇疆鏂囦欢鍏充簬cos鐨勯厤缃�
+ *
+ * @author锛歺p
+ * @date锛�2025/5/16 16:23
+ */
+@Configuration
+@ConfigurationProperties(prefix = "cos")
+public class COSConfigProperty {
+
+    /** 鑵捐ARM鐢ㄦ埛鐨剆ecretId */
+    private String secretId;
+
+    /** 鑵捐ARM鐢ㄦ埛鐨剆ecretKey */
+    private String secretKey;
+
+    /** STS涓存椂璁块棶鍑瘉鏈夋晥鏈燂紝鍗曚綅绉掞紝榛樿1800s锛屼富璐﹀彿鏈�闀�2灏忔椂锛屽瓙璐﹀彿(ARM鐢ㄦ埛)36灏忔椂 */
+    private Integer durationSeconds;
+
+    /** bucket鎵�鍦ㄧ殑鍦板煙 */
+    private String region;
+
+    /** bucket鍚嶇О */
+    private String bucket;
+
+    /** 棰勭鍚島rl杩囨湡鏃堕棿锛堝垎閽燂級 */
+    private Integer urlExpireMinute;
+
+    /** sts鐨勬潈闄� */
+    private String[] actions;
+
+    /** sts鑳芥搷浣滅殑璧勬簮 */
+    private String[] resources;
+
+    public String getSecretId() {
+        return secretId;
+    }
+
+    public void setSecretId(String secretId) {
+        this.secretId = secretId;
+    }
+
+    public String getSecretKey() {
+        return secretKey;
+    }
+
+    public void setSecretKey(String secretKey) {
+        this.secretKey = secretKey;
+    }
+
+    public Integer getDurationSeconds() {
+        return durationSeconds;
+    }
+
+    public void setDurationSeconds(Integer durationSeconds) {
+        this.durationSeconds = durationSeconds;
+    }
+
+    public String getRegion() {
+        return region;
+    }
+
+    public void setRegion(String region) {
+        this.region = region;
+    }
+
+    public String getBucket() {
+        return bucket;
+    }
+
+    public void setBucket(String bucket) {
+        this.bucket = bucket;
+    }
+
+    public String[] getActions() {
+        return actions;
+    }
+
+    public void setActions(String[] actions) {
+        this.actions = actions;
+    }
+
+    public String[] getResources() {
+        return resources;
+    }
+
+    public void setResources(String[] resources) {
+        this.resources = resources;
+    }
+
+    public Integer getUrlExpireMinute() {
+        return urlExpireMinute;
+    }
+
+    public void setUrlExpireMinute(Integer urlExpireMinute) {
+        this.urlExpireMinute = urlExpireMinute;
+    }
+}
diff --git a/framework/src/main/java/cn/lili/cos/CosSTS.java b/framework/src/main/java/cn/lili/cos/CosSTS.java
new file mode 100644
index 0000000..ae955e1
--- /dev/null
+++ b/framework/src/main/java/cn/lili/cos/CosSTS.java
@@ -0,0 +1,40 @@
+package cn.lili.cos;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * sts涓存椂璁块棶鍑瘉瀵硅薄
+ * @author锛歺p
+ * @date锛�2025/5/16 16:33
+ */
+@Data
+@ApiModel("STS涓存椂璁块棶鍑瘉")
+public class CosSTS {
+
+    @ApiModelProperty("涓存椂瀵嗛挜id")
+    private String tmpSecretId;
+
+    @ApiModelProperty("涓存椂瀵嗛挜key")
+    private String tmpSecretKey;
+
+    @ApiModelProperty("sts-token")
+    private String sessionToken;
+
+    @ApiModelProperty("sts璧锋晥鏃堕棿")
+    private Long stsStartTime;
+
+    @ApiModelProperty("sts澶辨晥鏃堕棿")
+    private Long stsEndTime;
+
+    @ApiModelProperty("bucket")
+    private String bucket;
+
+    @ApiModelProperty("region")
+    private String region;
+
+
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/domain/entity/LmkFile.java b/framework/src/main/java/cn/lili/modules/lmk/domain/entity/LmkFile.java
new file mode 100644
index 0000000..d8fef08
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/domain/entity/LmkFile.java
@@ -0,0 +1,38 @@
+package cn.lili.modules.lmk.domain.entity;
+
+import cn.lili.mybatis.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import lombok.Data;
+
+/**
+ * 鏂囦欢淇℃伅
+ *
+ * @author xp
+ * @since 2025-05-19
+ */
+@Data
+@TableName("lmk_file")
+public class LmkFile extends BaseEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableField("file_key")
+    /** 鏂囦欢鍞竴鏍囪瘑 */
+    private String fileKey;
+
+    @TableField("file_type")
+    /** 鏂囦欢绫诲瀷 */
+    private String fileType;
+
+    @TableField("file_size")
+    /** 鏂囦欢澶у皬 */
+    private Long fileSize;
+
+    @TableField("original_filename")
+    /** 鏂囦欢鍘熷鍚� */
+    private String originalFileName;
+
+
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/domain/entity/Video.java b/framework/src/main/java/cn/lili/modules/lmk/domain/entity/Video.java
new file mode 100644
index 0000000..6d6bb46
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/domain/entity/Video.java
@@ -0,0 +1,83 @@
+package cn.lili.modules.lmk.domain.entity;
+
+import cn.lili.mybatis.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import java.time.LocalDateTime;
+import lombok.Data;
+
+/**
+ * 瑙嗛鍐呭
+ *
+ * @author xp
+ * @since 2025-05-16
+ */
+@Data
+@TableName("lmk_video")
+public class Video extends BaseEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableField("author_id")
+    /** 浣滆�卛d */
+    private String authorId;
+
+    @TableField("cover_url")
+    /** 鍥剧墖灏侀潰 */
+    private String coverUrl;
+
+    @TableField("video_file_key")
+    /** 瑙嗛鍦板潃 */
+    private String videoFileKey;
+
+    @TableField("video_fit")
+    /** 瑙嗛濉厖妯″紡 */
+    private String videoFit;
+
+    @TableField("title")
+    /** 瑙嗛鏍囬 */
+    private String title;
+
+    @TableField("goods_id")
+    /** 鍟嗗搧id */
+    private String goodsId;
+
+    @TableField("goods_view_num")
+    /** 鍟嗗搧鏌ョ湅娆℃暟 */
+    private Long goodsViewNum;
+
+    @TableField("goods_order_num")
+    /** 鍟嗗搧涓嬪崟娆℃暟 */
+    private Long goodsOrderNum;
+
+    @TableField("recommend")
+    /** 鏄惁鎺ㄨ崘 */
+    private Boolean recommend;
+
+    @TableField("status")
+    /** 鐘舵�� */
+    private String status;
+
+    @TableField("play_num")
+    /** 鎾斁閲� */
+    private Long playNum;
+
+    @TableField("collect_num")
+    /** 鏀惰棌鏁� */
+    private Long collectNum;
+
+    @TableField("comment_num")
+    /** 璇勮鏁� */
+    private Long commentNum;
+
+    @TableField("weight")
+    /** 鏉冮噸 */
+    private Double weight;
+
+    @TableField("audit_pass_time")
+    /** 瀹℃牳閫氳繃鏃堕棿 */
+    private LocalDateTime auditPassTime;
+
+
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/domain/entity/VideoTag.java b/framework/src/main/java/cn/lili/modules/lmk/domain/entity/VideoTag.java
index 4c2de3b..7ffb17f 100644
--- a/framework/src/main/java/cn/lili/modules/lmk/domain/entity/VideoTag.java
+++ b/framework/src/main/java/cn/lili/modules/lmk/domain/entity/VideoTag.java
@@ -26,5 +26,8 @@
     /** 鍒涘缓鏂瑰紡 */
     private String createType;
 
+    @TableField("use_num")
+    /** 瑙嗛寮曠敤娆℃暟 */
+    private Long useNum;
 
 }
diff --git a/framework/src/main/java/cn/lili/modules/lmk/domain/entity/VideoTagRef.java b/framework/src/main/java/cn/lili/modules/lmk/domain/entity/VideoTagRef.java
new file mode 100644
index 0000000..13ff0fb
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/domain/entity/VideoTagRef.java
@@ -0,0 +1,31 @@
+package cn.lili.modules.lmk.domain.entity;
+
+import cn.lili.mybatis.BaseEntity;
+import cn.lili.mybatis.BaseIdEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import lombok.Data;
+
+/**
+ * 瑙嗛鏍囩涓棿琛�
+ *
+ * @author xp
+ * @since 2025-05-19
+ */
+@Data
+@TableName("lmk_video_tag_ref")
+public class VideoTagRef extends BaseIdEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableField("video_id")
+    /** 瑙嗛id */
+    private String videoId;
+
+    @TableField("video_tag_id")
+    /** 瑙嗛鏍囩id */
+    private String videoTagId;
+
+
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/domain/form/FileInfoForm.java b/framework/src/main/java/cn/lili/modules/lmk/domain/form/FileInfoForm.java
new file mode 100644
index 0000000..eebf1e0
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/domain/form/FileInfoForm.java
@@ -0,0 +1,31 @@
+package cn.lili.modules.lmk.domain.form;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springframework.validation.annotation.Validated;
+
+/**
+ * 灏忕▼搴忕洿浼狅紝闇�瑕佹妸涓婁紶鐨勬枃浠朵俊鎭紶鍒板悗绔繚瀛�
+ *
+ * @author锛歺p
+ * @date锛�2025/5/19 15:17
+ */
+@Data
+@Validated
+@ApiModel("灏忕▼搴忕洿浼犳枃浠朵俊鎭�")
+public class FileInfoForm {
+
+    @ApiModelProperty("鏂囦欢鏍囪瘑")
+    private String fileKey;
+
+    @ApiModelProperty("鏂囦欢绫诲瀷")
+    private String fileType;
+
+    @ApiModelProperty("鏂囦欢澶у皬")
+    private Long fileSize;
+
+    @ApiModelProperty("鏂囦欢鍘熷鍚�")
+    private String originalFileName;
+
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/domain/form/VideoForm.java b/framework/src/main/java/cn/lili/modules/lmk/domain/form/VideoForm.java
new file mode 100644
index 0000000..a349f7e
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/domain/form/VideoForm.java
@@ -0,0 +1,64 @@
+package cn.lili.modules.lmk.domain.form;
+
+import cn.lili.group.Update;
+import cn.lili.group.Add;
+import cn.lili.base.AbsForm;
+import cn.lili.modules.lmk.domain.entity.Video;
+import org.hibernate.validator.constraints.Length;
+import org.springframework.beans.BeanUtils;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import org.springframework.lang.NonNull;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 瑙嗛鍐呭琛ㄥ崟
+ *
+ * @author xp
+ * @since 2025-05-16
+ */
+@Data
+@ApiModel(value = "Video琛ㄥ崟", description = "瑙嗛鍐呭琛ㄥ崟")
+public class VideoForm extends AbsForm {
+
+
+    @NotBlank(message = "瑙嗛涓嶈兘涓虹┖", groups = {Add.class, Update.class})
+    @ApiModelProperty("瑙嗛")
+    private String videoFileKey;
+
+    @NotBlank(message = "鏍囬涓嶈兘涓虹┖", groups = {Add.class, Update.class})
+    @ApiModelProperty("鏍囬")
+    private String title;
+
+    @ApiModelProperty("瑙嗛鏍囩")
+    @Length(max = 5, message = "鏈�澶氬彧鑳芥坊鍔犱簲涓爣绛�")
+    private List<WxVideoTagForm> tags = new ArrayList<>(2);
+
+//    @NotBlank(message = "鍟嗗搧id涓嶈兘涓虹┖", groups = {Add.class, Update.class})
+    @ApiModelProperty("鍟嗗搧id")
+    private String goodsId;
+
+    @ApiModelProperty("瑙嗛濉厖妯″紡")
+    private String videoFit;
+
+    @ApiModelProperty("鏂囦欢淇℃伅")
+    @Valid
+    private FileInfoForm fileInfo;
+
+    public static Video getEntityByForm(@NonNull VideoForm form, Video entity) {
+        if(entity == null) {
+          entity = new Video();
+        }
+        BeanUtils.copyProperties(form, entity);
+        return entity;
+    }
+
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/domain/form/WxVideoTagForm.java b/framework/src/main/java/cn/lili/modules/lmk/domain/form/WxVideoTagForm.java
new file mode 100644
index 0000000..ec9aae7
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/domain/form/WxVideoTagForm.java
@@ -0,0 +1,30 @@
+package cn.lili.modules.lmk.domain.form;
+
+import cn.lili.base.AbsForm;
+import cn.lili.group.Add;
+import cn.lili.group.Update;
+import cn.lili.modules.lmk.domain.entity.VideoTag;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springframework.beans.BeanUtils;
+import org.springframework.lang.NonNull;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+/**
+ * 瑙嗛鏍囩琛ㄥ崟
+ *
+ * @author xp
+ * @since 2025-05-13
+ */
+@Data
+@ApiModel(value = "VideoTag琛ㄥ崟", description = "瑙嗛鏍囩琛ㄥ崟")
+public class WxVideoTagForm extends AbsForm {
+
+    @ApiModelProperty("鏍囩鍚嶇О")
+    private String tagName;
+
+
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/domain/query/VideoQuery.java b/framework/src/main/java/cn/lili/modules/lmk/domain/query/VideoQuery.java
new file mode 100644
index 0000000..df533f0
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/domain/query/VideoQuery.java
@@ -0,0 +1,22 @@
+package cn.lili.modules.lmk.domain.query;
+
+import cn.lili.base.AbsQuery;
+import java.util.List;
+import org.springframework.lang.NonNull;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 瑙嗛鍐呭鏌ヨ
+ *
+ * @author xp
+ * @since 2025-05-16
+ */
+@Data
+@ApiModel(value = "Video鏌ヨ鍙傛暟", description = "瑙嗛鍐呭鏌ヨ鍙傛暟")
+public class VideoQuery extends AbsQuery {
+}
+
diff --git a/framework/src/main/java/cn/lili/modules/lmk/domain/query/WxVideoTagQuery.java b/framework/src/main/java/cn/lili/modules/lmk/domain/query/WxVideoTagQuery.java
new file mode 100644
index 0000000..61db0e5
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/domain/query/WxVideoTagQuery.java
@@ -0,0 +1,25 @@
+package cn.lili.modules.lmk.domain.query;
+
+import cn.lili.base.AbsQuery;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 瑙嗛鏍囩鏌ヨ
+ *
+ * @author xp
+ * @since 2025-05-13
+ */
+@Data
+@ApiModel(value = "VideoTag鏌ヨ鍙傛暟", description = "瑙嗛鏍囩鏌ヨ鍙傛暟")
+public class WxVideoTagQuery {
+
+    @ApiModelProperty("鏍囩鍚嶇О")
+    private String tagName;
+
+    @ApiModelProperty("鎼滅储绫诲瀷锛欻OT锛堢儹闂ㄦ爣绛撅級銆丼EARCH锛堟牴鎹緭鍏ョ殑鏍囩鍚嶇О鎼滅储锛�")
+    private String searchType = "HOT";
+
+}
+
diff --git a/framework/src/main/java/cn/lili/modules/lmk/domain/vo/LmkFileVO.java b/framework/src/main/java/cn/lili/modules/lmk/domain/vo/LmkFileVO.java
new file mode 100644
index 0000000..6801b90
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/domain/vo/LmkFileVO.java
@@ -0,0 +1,49 @@
+package cn.lili.modules.lmk.domain.vo;
+
+import cn.lili.base.AbsVo;
+import cn.lili.modules.lmk.domain.entity.LmkFile;
+import lombok.experimental.Accessors;
+import org.springframework.lang.NonNull;
+import org.springframework.beans.BeanUtils;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 鏂囦欢淇℃伅灞曠ず
+ *
+ * @author xp
+ * @since 2025-05-19
+ */
+@Data
+@Accessors(chain = true)
+@ApiModel(value = "鏂囦欢淇℃伅鍝嶅簲鏁版嵁", description = "鏂囦欢淇℃伅鍝嶅簲鏁版嵁")
+public class LmkFileVO extends AbsVo {
+
+    /**
+     * 涓存椂璁块棶閾炬帴
+     */
+    @ApiModelProperty("涓存椂璁块棶閾炬帴")
+    private String url;
+
+    /**
+     * fileKey鏁版嵁搴撲繚瀛樼殑鍊�
+     */
+    @ApiModelProperty("鏂囦欢鏍囪瘑")
+    private String fileKey;
+
+    /**
+     * 鏂囦欢鍚�
+     */
+    @ApiModelProperty("鏂囦欢鍘熷鍚�")
+    private String originalName;
+
+    public static LmkFileVO getVoByEntity(@NonNull LmkFile entity, LmkFileVO vo) {
+        if(vo == null) {
+            vo = new LmkFileVO();
+        }
+        BeanUtils.copyProperties(entity, vo);
+        return vo;
+    }
+
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/domain/vo/VideoVO.java b/framework/src/main/java/cn/lili/modules/lmk/domain/vo/VideoVO.java
new file mode 100644
index 0000000..77801db
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/domain/vo/VideoVO.java
@@ -0,0 +1,91 @@
+package cn.lili.modules.lmk.domain.vo;
+
+import cn.lili.base.AbsVo;
+import cn.lili.modules.lmk.domain.entity.Video;
+import java.util.List;
+import org.springframework.lang.NonNull;
+import org.springframework.beans.BeanUtils;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import java.util.Date;
+
+/**
+ * 瑙嗛鍐呭灞曠ず
+ *
+ * @author xp
+ * @since 2025-05-16
+ */
+@Data
+@ApiModel(value = "瑙嗛鍐呭鍝嶅簲鏁版嵁", description = "瑙嗛鍐呭鍝嶅簲鏁版嵁")
+public class VideoVO extends AbsVo {
+
+    /** 浣滆�卛d */
+    @ApiModelProperty("浣滆�卛d")
+    private String authorId;
+
+    /** 鍥剧墖灏侀潰 */
+    @ApiModelProperty("鍥剧墖灏侀潰")
+    private String coverUrl;
+
+    /** 瑙嗛鍦板潃 */
+    @ApiModelProperty("瑙嗛鍦板潃")
+    private String videoFileKey;
+
+    /** 瑙嗛濉厖妯″紡 */
+    @ApiModelProperty("瑙嗛濉厖妯″紡")
+    private String videoFit;
+
+    /** 瑙嗛鏍囬 */
+    @ApiModelProperty("瑙嗛鏍囬")
+    private String title;
+
+    /** 鍟嗗搧id */
+    @ApiModelProperty("鍟嗗搧id")
+    private String goodsId;
+
+    /** 鍟嗗搧鏌ョ湅娆℃暟 */
+    @ApiModelProperty("鍟嗗搧鏌ョ湅娆℃暟")
+    private Long goodsViewNum;
+
+    /** 鍟嗗搧涓嬪崟娆℃暟 */
+    @ApiModelProperty("鍟嗗搧涓嬪崟娆℃暟")
+    private Long goodsOrderNum;
+
+    /** 鏄惁鎺ㄨ崘 */
+    @ApiModelProperty("鏄惁鎺ㄨ崘")
+    private Boolean recommend;
+
+    /** 鐘舵�� */
+    @ApiModelProperty("鐘舵��")
+    private String status;
+
+    /** 鎾斁閲� */
+    @ApiModelProperty("鎾斁閲�")
+    private Long playNum;
+
+    /** 鏀惰棌鏁� */
+    @ApiModelProperty("鏀惰棌鏁�")
+    private Long collectNum;
+
+    /** 璇勮鏁� */
+    @ApiModelProperty("璇勮鏁�")
+    private Long commentNum;
+
+    /** 鏉冮噸 */
+    @ApiModelProperty("鏉冮噸")
+    private double weight;
+
+    /** 瀹℃牳閫氳繃鏃堕棿 */
+    @ApiModelProperty("瀹℃牳閫氳繃鏃堕棿")
+    private Date auditPassTime;
+
+    public static VideoVO getVoByEntity(@NonNull Video entity, VideoVO vo) {
+        if(vo == null) {
+            vo = new VideoVO();
+        }
+        BeanUtils.copyProperties(entity, vo);
+        return vo;
+    }
+
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/enums/general/FileTypeEnum.java b/framework/src/main/java/cn/lili/modules/lmk/enums/general/FileTypeEnum.java
new file mode 100644
index 0000000..def0682
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/enums/general/FileTypeEnum.java
@@ -0,0 +1,54 @@
+package cn.lili.modules.lmk.enums.general;
+
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * oss鏂囦欢鍒嗙被鐩綍锛屾枃浠剁被鍨嬬櫧鍚嶅崟
+ * @author 29443
+ *
+ */
+
+public enum FileTypeEnum {
+
+    IMAGE("image", "鍥剧墖", Arrays.asList("jpg", "png", "jpeg", "gif", "bmp", "webp", "tiff", "svg", "ico", "psd", "raw")),
+
+    VIDEO("video", "瑙嗛", Arrays.asList("mp4", "avi", "rmvb", "mov", "wmv", "flv", "mkv", "mpeg", "mpg", "m4v", "3gp", "webm", "vob", "swf")),
+
+    RADIO("radio", "闊抽", Arrays.asList("mp3", "wma", "wav", "mpeg-4", "cd", "m4a", "aac", "flac", "ogg", "aiff", "ape", "midi", "amr", "ra")),
+
+    TEXT("text", "鏂囨湰鏂囦欢", Arrays.asList("txt", "xls", "xlsx", "doc", "docx", "pdf", "ppt", "pptx", "csv", "rtf", "odt", "ods", "odp", "epub", "mobi", "pages", "numbers", "key")),
+
+    ZIP("zip", "鍘嬬缉鏂囦欢", Arrays.asList("zip", "rar", "7z", "tar", "gz", "bz2", "xz", "iso", "dmg", "pkg", "cab", "z", "lz", "lzma", "lzo")),
+    ;
+
+    /**
+     * 绫诲瀷
+     */
+    private final String type;
+
+    /**
+     * 绫诲瀷瀵瑰簲鐨勫悗缂�
+     */
+    private final List<String> suffixs;
+
+    /**
+     * 鎻忚堪
+     */
+    private final String desc;
+
+    FileTypeEnum(String type, String desc, List<String> suffixs) {
+        this.type = type;
+        this.suffixs = suffixs;
+        this.desc = desc;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public List<String> getSuffixs() {
+        return suffixs;
+    }
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/enums/general/VideoStatusEnum.java b/framework/src/main/java/cn/lili/modules/lmk/enums/general/VideoStatusEnum.java
new file mode 100644
index 0000000..054913a
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/enums/general/VideoStatusEnum.java
@@ -0,0 +1,48 @@
+package cn.lili.modules.lmk.enums.general;
+
+import lombok.Getter;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 瑙嗛鏍囩鏉ユ簮
+ *
+ * @author锛歺p
+ * @date锛�2025/5/14 10:30
+ */
+@Getter
+public enum VideoStatusEnum {
+
+    AUDITING("99", "瀹℃牳涓�"),
+    PUBLISHED("1", "宸插彂甯�"),
+    DISABLE("0", "宸蹭笅鏋�"),
+    REJECT("-1", "瀹℃牳鏈�氳繃"),
+    ;
+
+    private final String value;
+
+
+    private final String desc;
+
+    VideoStatusEnum(String value, String desc) {
+        this.value = value;
+        this.desc = desc;
+    }
+
+    /**
+     * 鑾峰彇鍚箟
+     *
+     * @param value
+     * @return
+     */
+    public static String getDescByValue(String value) {
+        if (StringUtils.isBlank(value)) {
+            return null;
+        }
+        for (VideoStatusEnum e : VideoStatusEnum.values()){
+            if (value.equals(e.getValue())) {
+                return e.getDesc();
+            }
+        }
+        return null;
+    }
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/mapper/LmkFileMapper.java b/framework/src/main/java/cn/lili/modules/lmk/mapper/LmkFileMapper.java
new file mode 100644
index 0000000..e44444f
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/mapper/LmkFileMapper.java
@@ -0,0 +1,26 @@
+package cn.lili.modules.lmk.mapper;
+
+import cn.lili.modules.lmk.domain.entity.LmkFile;
+import cn.lili.modules.lmk.domain.vo.LmkFileVO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 鏂囦欢淇℃伅 Mapper 鎺ュ彛
+ *
+ * @author xp
+ * @since 2025-05-19
+ */
+@Mapper
+public interface LmkFileMapper extends BaseMapper<LmkFile> {
+
+    /**
+     * 鏌ユ壘鏂囦欢淇℃伅
+     *
+     * @param fileKey
+     * @return
+     */
+    LmkFile getByFileKey(String fileKey);
+
+
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/mapper/VideoMapper.java b/framework/src/main/java/cn/lili/modules/lmk/mapper/VideoMapper.java
new file mode 100644
index 0000000..33a8bd5
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/mapper/VideoMapper.java
@@ -0,0 +1,34 @@
+package cn.lili.modules.lmk.mapper;
+
+import cn.lili.modules.lmk.domain.entity.Video;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import cn.lili.modules.lmk.domain.vo.VideoVO;
+import cn.lili.modules.lmk.domain.form.VideoForm;
+import cn.lili.modules.lmk.domain.query.VideoQuery;
+import java.util.List;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * 瑙嗛鍐呭 Mapper 鎺ュ彛
+ *
+ * @author xp
+ * @since 2025-05-16
+ */
+@Mapper
+public interface VideoMapper extends BaseMapper<Video> {
+
+    /**
+     * id鏌ユ壘瑙嗛鍐呭
+     * @param id
+     * @return
+     */
+    VideoVO getById(Integer id);
+
+    /**
+    *  鍒嗛〉
+    */
+    IPage getPage(IPage page, @Param("query") VideoQuery query);
+
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/mapper/VideoTagRefMapper.java b/framework/src/main/java/cn/lili/modules/lmk/mapper/VideoTagRefMapper.java
new file mode 100644
index 0000000..7548bf6
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/mapper/VideoTagRefMapper.java
@@ -0,0 +1,17 @@
+package cn.lili.modules.lmk.mapper;
+
+import cn.lili.modules.lmk.domain.entity.VideoTagRef;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 瑙嗛鏍囩涓棿琛� Mapper 鎺ュ彛
+ *
+ * @author xp
+ * @since 2025-05-19
+ */
+@Mapper
+public interface VideoTagRefMapper extends BaseMapper<VideoTagRef> {
+
+
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/service/LmkFileService.java b/framework/src/main/java/cn/lili/modules/lmk/service/LmkFileService.java
new file mode 100644
index 0000000..bdc3b61
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/service/LmkFileService.java
@@ -0,0 +1,83 @@
+package cn.lili.modules.lmk.service;
+
+import cn.lili.base.Result;
+import cn.lili.cos.CosSTS;
+import cn.lili.modules.lmk.domain.entity.LmkFile;
+import cn.lili.modules.lmk.domain.form.FileInfoForm;
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * 鏂囦欢淇℃伅 鏈嶅姟绫�
+ *
+ * @author xp
+ * @since 2025-05-19
+ */
+public interface LmkFileService extends IService<LmkFile> {
+
+    /**
+     * 涓婁紶鍗曚釜鏂囦欢
+     *
+     * @param file
+     * @return
+     */
+    Result uploadObject(MultipartFile file);
+
+    /**
+     * 涓婁紶澶氫釜鏂囦欢
+     *
+     * @param files
+     * @return
+     */
+    Result uploadObjects(List<MultipartFile> files);
+
+    /**
+     * 鍒犻櫎鍗曚釜鏂囦欢
+     *
+     * @param fileKey
+     * @return
+     */
+    Result deleteObject(String fileKey);
+
+    /**
+     * 鍒犻櫎澶氫釜鏂囦欢
+     *
+     * @param fileKeys
+     * @return
+     */
+    Result deleteObjects(List<String> fileKeys);
+
+    /**
+     * 涓嬭浇鏂囦欢
+     *
+     * @param fileKey
+     * @param response
+     * @return
+     */
+    void downloadObject(String fileKey, HttpServletResponse response);
+
+    /**
+     * 棰勮鏂囦欢
+     *
+     * @param fileKey
+     * @return
+     */
+    String getPreviewUrl(String fileKey);
+
+    /**
+     * 鑾峰彇sts涓存椂璁块棶鍑瘉
+     *
+     * @return
+     */
+    CosSTS getSTSToken();
+
+    /**
+     * 淇濆瓨鏂囦欢淇℃伅
+     *
+     * @param fileInfo
+     */
+    void addByForm(FileInfoForm fileInfo);
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/service/VideoService.java b/framework/src/main/java/cn/lili/modules/lmk/service/VideoService.java
new file mode 100644
index 0000000..583109b
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/service/VideoService.java
@@ -0,0 +1,73 @@
+package cn.lili.modules.lmk.service;
+
+import cn.lili.modules.lmk.domain.entity.Video;
+import com.baomidou.mybatisplus.extension.service.IService;
+import cn.lili.base.Result;
+import cn.lili.modules.lmk.domain.form.VideoForm;
+import cn.lili.modules.lmk.domain.query.VideoQuery;
+import java.util.List;
+
+/**
+ * 瑙嗛鍐呭 鏈嶅姟绫�
+ *
+ * @author xp
+ * @since 2025-05-16
+ */
+public interface VideoService extends IService<Video> {
+
+    /**
+     * 娣诲姞
+     * @param form
+     * @return
+     */
+    Result add(VideoForm form);
+
+    /**
+     * 淇敼
+     * @param form
+     * @return
+     */
+    Result update(VideoForm form);
+
+    /**
+     * 鎵归噺鍒犻櫎
+     * @param ids
+     * @return
+     */
+    Result remove(List<String> ids);
+
+    /**
+     * id鍒犻櫎
+     * @param id
+     * @return
+     */
+    Result removeById(String id);
+
+    /**
+     * 鍒嗛〉鏌ヨ
+     * @param query
+     * @return
+     */
+    Result page(VideoQuery query);
+
+    /**
+     * 鏍规嵁id鏌ユ壘
+     * @param id
+     * @return
+     */
+    Result detail(Integer id);
+
+    /**
+     * 鍒楄〃
+     * @return
+     */
+    Result all();
+
+    /**
+     * 鍙戝竷瑙嗛
+     *
+     * @param form
+     * @return
+     */
+    Result publish(VideoForm form);
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/service/VideoTagRefService.java b/framework/src/main/java/cn/lili/modules/lmk/service/VideoTagRefService.java
new file mode 100644
index 0000000..a07e767
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/service/VideoTagRefService.java
@@ -0,0 +1,15 @@
+package cn.lili.modules.lmk.service;
+
+import cn.lili.modules.lmk.domain.entity.VideoTagRef;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * 瑙嗛鏍囩涓棿琛� 鏈嶅姟绫�
+ *
+ * @author xp
+ * @since 2025-05-19
+ */
+public interface VideoTagRefService extends IService<VideoTagRef> {
+
+
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/service/VideoTagService.java b/framework/src/main/java/cn/lili/modules/lmk/service/VideoTagService.java
index 08cf306..0395373 100644
--- a/framework/src/main/java/cn/lili/modules/lmk/service/VideoTagService.java
+++ b/framework/src/main/java/cn/lili/modules/lmk/service/VideoTagService.java
@@ -1,6 +1,7 @@
 package cn.lili.modules.lmk.service;
 
 import cn.lili.modules.lmk.domain.entity.VideoTag;
+import cn.lili.modules.lmk.domain.query.WxVideoTagQuery;
 import com.baomidou.mybatisplus.extension.service.IService;
 import cn.lili.base.Result;
 import cn.lili.modules.lmk.domain.form.VideoTagForm;
@@ -62,4 +63,12 @@
      * @return
      */
     Result all();
+
+    /**
+     * 鎺ㄨ崘鏍囩
+     *
+     * @param query
+     * @return
+     */
+    Result recommend(WxVideoTagQuery query);
 }
diff --git a/framework/src/main/java/cn/lili/modules/lmk/service/impl/LmkFileServiceImpl.java b/framework/src/main/java/cn/lili/modules/lmk/service/impl/LmkFileServiceImpl.java
new file mode 100644
index 0000000..4076c84
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/service/impl/LmkFileServiceImpl.java
@@ -0,0 +1,93 @@
+package cn.lili.modules.lmk.service.impl;
+
+import cn.lili.base.Result;
+import cn.lili.common.exception.ServiceException;
+import cn.lili.cos.CosSTS;
+import cn.lili.modules.lmk.domain.entity.LmkFile;
+import cn.lili.modules.lmk.domain.form.FileInfoForm;
+import cn.lili.modules.lmk.domain.vo.LmkFileVO;
+import cn.lili.modules.lmk.mapper.LmkFileMapper;
+import cn.lili.modules.lmk.service.LmkFileService;
+import cn.lili.utils.COSUtil;
+import cn.lili.utils.FileUtil;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * 鏂囦欢淇℃伅 鏈嶅姟瀹炵幇绫�
+ *
+ * @author xp
+ * @since 2025-05-19
+ */
+@Service
+@RequiredArgsConstructor
+public class LmkFileServiceImpl extends ServiceImpl<LmkFileMapper, LmkFile> implements LmkFileService {
+
+    private final LmkFileMapper lmkFileMapper;
+    private final COSUtil cosUtil;
+
+
+    @Override
+    public Result uploadObject(MultipartFile file) {
+        LmkFile fileInfo = FileUtil.getFileInfo(file);
+        try {
+            cosUtil.upload(file.getInputStream(), fileInfo);
+            lmkFileMapper.insert(fileInfo);
+        } catch (IOException e) {
+            e.printStackTrace();
+            throw new ServiceException("涓婁紶寮傚父锛岃閲嶈瘯");
+        }
+        String url = cosUtil.getPreviewUrl(fileInfo.getFileKey());
+        LmkFileVO fileVo = new LmkFileVO().setUrl(url).setFileKey(fileInfo.getFileKey());
+        return Result.ok("涓婁紶鎴愬姛").data(fileVo);
+    }
+
+    @Override
+    public Result uploadObjects(List<MultipartFile> files) {
+        return null;
+    }
+
+    @Override
+    public Result deleteObject(String fileKey) {
+        cosUtil.deleteFile(fileKey);
+        return Result.ok("鍒犻櫎鎴愬姛");
+    }
+
+    @Override
+    public Result deleteObjects(List<String> fileKeys) {
+        cosUtil.deleteFiles(fileKeys);
+        return Result.ok("鍒犻櫎鎴愬姛");
+    }
+
+    @Override
+    public void downloadObject(String fileKey, HttpServletResponse response) {
+        cosUtil.download(fileKey, response);
+    }
+
+    @Override
+    public String getPreviewUrl(String fileKey) {
+        return cosUtil.getPreviewUrl(fileKey);
+    }
+
+    @Override
+    public CosSTS getSTSToken() {
+        return cosUtil.getSTS();
+    }
+
+    @Override
+    @Transactional(propagation = Propagation.REQUIRED)
+    public void addByForm(FileInfoForm fileInfo) {
+        LmkFile file = new LmkFile();
+        BeanUtils.copyProperties(fileInfo, file);
+        baseMapper.insert(file);
+    }
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/service/impl/VideoServiceImpl.java b/framework/src/main/java/cn/lili/modules/lmk/service/impl/VideoServiceImpl.java
new file mode 100644
index 0000000..f2f75a8
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/service/impl/VideoServiceImpl.java
@@ -0,0 +1,171 @@
+package cn.lili.modules.lmk.service.impl;
+
+import cn.lili.common.security.context.UserContext;
+import cn.lili.modules.lmk.domain.entity.LmkFile;
+import cn.lili.modules.lmk.domain.entity.VideoTag;
+import cn.lili.modules.lmk.domain.entity.VideoTagRef;
+import cn.lili.modules.lmk.enums.general.TagCreateTypeEnum;
+import cn.lili.modules.lmk.enums.general.VideoStatusEnum;
+import cn.lili.modules.lmk.service.LmkFileService;
+import cn.lili.modules.lmk.service.VideoTagRefService;
+import cn.lili.modules.lmk.service.VideoTagService;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import cn.lili.modules.lmk.domain.entity.Video;
+import cn.lili.modules.lmk.mapper.VideoMapper;
+import cn.lili.modules.lmk.service.VideoService;
+import cn.lili.base.Result;
+import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import cn.lili.modules.lmk.domain.form.VideoForm;
+import cn.lili.modules.lmk.domain.vo.VideoVO;
+import cn.lili.modules.lmk.domain.query.VideoQuery;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+import lombok.RequiredArgsConstructor;
+import cn.lili.utils.PageUtil;
+import org.springframework.beans.BeanUtils;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.Assert;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * 瑙嗛鍐呭 鏈嶅姟瀹炵幇绫�
+ *
+ * @author xp
+ * @since 2025-05-16
+ */
+@Service
+@RequiredArgsConstructor
+public class VideoServiceImpl extends ServiceImpl<VideoMapper, Video> implements VideoService {
+
+    private final VideoMapper videoMapper;
+    private final VideoTagService videoTagService;
+    private final VideoTagRefService videoTagRefService;
+    private final LmkFileService lmkFileService;
+
+    /**
+     * 娣诲姞
+     * @param form
+     * @return
+     */
+    @Override
+    public Result add(VideoForm form) {
+        Video entity = VideoForm.getEntityByForm(form, null);
+        baseMapper.insert(entity);
+        return Result.ok("娣诲姞鎴愬姛");
+    }
+
+    /**
+     * 淇敼
+     * @param form
+     * @return
+     */
+    @Override
+    public Result update(VideoForm form) {
+        Video entity = baseMapper.selectById(form.getId());
+
+        // 涓虹┖鎶汭llegalArgumentException锛屽仛鍏ㄥ眬寮傚父澶勭悊
+        Assert.notNull(entity, "璁板綍涓嶅瓨鍦�");
+        BeanUtils.copyProperties(form, entity);
+        baseMapper.updateById(entity);
+        return Result.ok("淇敼鎴愬姛");
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎
+     * @param ids
+     * @return
+     */
+    @Override
+    public Result remove(List<String> ids) {
+        baseMapper.deleteBatchIds(ids);
+        return Result.ok("鍒犻櫎鎴愬姛");
+    }
+
+    /**
+     * id鍒犻櫎
+     * @param id
+     * @return
+     */
+    @Override
+    public Result removeById(String id) {
+        baseMapper.deleteById(id);
+        return Result.ok("鍒犻櫎鎴愬姛");
+    }
+
+    /**
+     * 鍒嗛〉鏌ヨ
+     * @param query
+     * @return
+     */
+    @Override
+    public Result page(VideoQuery query) {
+        IPage<VideoVO> page = PageUtil.getPage(query, VideoVO.class);
+        baseMapper.getPage(page, query);
+        return Result.ok().data(page.getRecords()).total(page.getTotal());
+    }
+
+    /**
+     * 鏍规嵁id鏌ユ壘
+     * @param id
+     * @return
+     */
+    @Override
+    public Result detail(Integer id) {
+        VideoVO vo = baseMapper.getById(id);
+        Assert.notNull(vo, "璁板綍涓嶅瓨鍦�");
+        return Result.ok().data(vo);
+    }
+
+    /**
+     * 鍒楄〃
+     * @return
+     */
+    @Override
+    public Result all() {
+        List<Video> entities = baseMapper.selectList(null);
+        List<VideoVO> vos = entities.stream()
+                .map(entity -> VideoVO.getVoByEntity(entity, null))
+                .collect(Collectors.toList());
+        return Result.ok().data(vos);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Result publish(VideoForm form) {
+        // 1.淇濆瓨瑙嗛
+        Video video = VideoForm.getEntityByForm(form, null);
+        video.setAuthorId(UserContext.getCurrentUserId());
+        video.setStatus(VideoStatusEnum.AUDITING.getValue());
+        baseMapper.insert(video);
+        // 2.澶勭悊鏍囩
+        List<VideoTagRef> videoTagRefs = form.getTags().stream().map(tag -> {
+            VideoTagRef videoTagRef = new VideoTagRef();
+            videoTagRef.setVideoId(video.getId());
+            if (StringUtils.isBlank(tag.getId())) {
+                VideoTag videoTag = new LambdaQueryChainWrapper<>(videoTagService.getBaseMapper())
+                        .eq(VideoTag::getTagName, tag.getTagName())
+                        .one();
+                if (Objects.nonNull(videoTag)) {
+                    videoTagRef.setVideoTagId(videoTag.getId());
+                } else {
+                    videoTag = new VideoTag();
+                    videoTag.setTagName(tag.getTagName());
+                    videoTag.setCreateType(TagCreateTypeEnum.USER.getValue());
+                    videoTagService.save(videoTag);
+                    videoTagRef.setVideoTagId(videoTag.getId());
+                }
+            } else {
+                videoTagRef.setVideoTagId(tag.getId());
+            }
+            return videoTagRef;
+        }).collect(Collectors.toList());
+        videoTagRefService.saveBatch(videoTagRefs);
+        // 3.淇濆瓨瑙嗛鏂囦欢淇℃伅
+        lmkFileService.addByForm(form.getFileInfo());
+        return Result.ok("鍙戝竷鎴愬姛锛岃棰戝鏍镐腑~");
+    }
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/service/impl/VideoTagRefServiceImpl.java b/framework/src/main/java/cn/lili/modules/lmk/service/impl/VideoTagRefServiceImpl.java
new file mode 100644
index 0000000..b727397
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/service/impl/VideoTagRefServiceImpl.java
@@ -0,0 +1,23 @@
+package cn.lili.modules.lmk.service.impl;
+
+import cn.lili.modules.lmk.domain.entity.VideoTagRef;
+import cn.lili.modules.lmk.mapper.VideoTagRefMapper;
+import cn.lili.modules.lmk.service.VideoTagRefService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+/**
+ * 瑙嗛鏍囩涓棿琛� 鏈嶅姟瀹炵幇绫�
+ *
+ * @author xp
+ * @since 2025-05-19
+ */
+@Service
+@RequiredArgsConstructor
+public class VideoTagRefServiceImpl extends ServiceImpl<VideoTagRefMapper, VideoTagRef> implements VideoTagRefService {
+
+    private final VideoTagRefMapper videoTagRefMapper;
+
+
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/service/impl/VideoTagServiceImpl.java b/framework/src/main/java/cn/lili/modules/lmk/service/impl/VideoTagServiceImpl.java
index 9702c31..baa1946 100644
--- a/framework/src/main/java/cn/lili/modules/lmk/service/impl/VideoTagServiceImpl.java
+++ b/framework/src/main/java/cn/lili/modules/lmk/service/impl/VideoTagServiceImpl.java
@@ -1,11 +1,13 @@
 package cn.lili.modules.lmk.service.impl;
 
+import cn.lili.modules.lmk.domain.query.WxVideoTagQuery;
 import cn.lili.modules.lmk.enums.general.TagCreateTypeEnum;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import cn.lili.modules.lmk.domain.entity.VideoTag;
 import cn.lili.modules.lmk.mapper.VideoTagMapper;
 import cn.lili.modules.lmk.service.VideoTagService;
 import cn.lili.base.Result;
+import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import cn.lili.modules.lmk.domain.form.VideoTagForm;
 import cn.lili.modules.lmk.domain.vo.VideoTagVO;
@@ -16,6 +18,7 @@
 import org.springframework.beans.BeanUtils;
 import org.springframework.util.Assert;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -121,4 +124,29 @@
                 .collect(Collectors.toList());
         return Result.ok().data(vos);
     }
+
+
+    @Override
+    public Result recommend(WxVideoTagQuery query) {
+        List<VideoTagVO> tags = new ArrayList<>(3);
+        switch (query.getSearchType()) {
+            case "HOT":
+                // TODO 鐑棬鏍囩閫氳繃瀹氭椂浠诲姟缁熻琛╨mk_video_tag_ref鏁伴噺鍒發mk_video_tag涓�
+                tags = new LambdaQueryChainWrapper<>(baseMapper)
+                        .orderByDesc(VideoTag::getUseNum)
+                        .last("limit 3")
+                        .list().stream().map(entity -> {
+                            return VideoTagVO.getVoByEntity(entity, null);
+                        }).collect(Collectors.toList());
+            case "SEARCH":
+                tags = new LambdaQueryChainWrapper<>(baseMapper)
+                        .orderByDesc(VideoTag::getUseNum)
+                        .like(VideoTag::getTagName, query.getTagName())
+                        .last("limit 3")
+                        .list().stream().map(entity -> {
+                            return VideoTagVO.getVoByEntity(entity, null);
+                        }).collect(Collectors.toList());
+        }
+        return Result.ok().data(tags);
+    }
 }
diff --git a/framework/src/main/java/cn/lili/utils/COSUtil.java b/framework/src/main/java/cn/lili/utils/COSUtil.java
new file mode 100644
index 0000000..23a2c23
--- /dev/null
+++ b/framework/src/main/java/cn/lili/utils/COSUtil.java
@@ -0,0 +1,285 @@
+package cn.lili.utils;
+
+import cn.lili.cos.COSConfigProperty;
+import cn.lili.cos.CosSTS;
+import cn.lili.modules.lmk.domain.entity.LmkFile;
+import com.qcloud.cos.COSClient;
+import com.qcloud.cos.ClientConfig;
+import com.qcloud.cos.auth.BasicSessionCredentials;
+import com.qcloud.cos.exception.CosClientException;
+import com.qcloud.cos.exception.CosServiceException;
+import com.qcloud.cos.http.HttpMethodName;
+import com.qcloud.cos.model.*;
+import com.qcloud.cos.region.Region;
+import com.tencent.cloud.CosStsClient;
+import com.tencent.cloud.Policy;
+import com.tencent.cloud.Response;
+import com.tencent.cloud.Statement;
+import com.tencent.cloud.cos.util.Jackson;
+import lombok.RequiredArgsConstructor;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.*;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author锛歺p
+ * @date锛�2025/5/16 16:31
+ */
+@Component
+@RequiredArgsConstructor
+public class COSUtil {
+
+    private final COSConfigProperty cosConfigProperty;
+
+    /**
+     * 鑾峰彇sts涓存椂璁块棶鍑瘉
+     *
+     * @return
+     */
+    public CosSTS getSTS() {
+        TreeMap<String, Object> config = new TreeMap<String, Object>();
+        try {
+            config.put("secretId", cosConfigProperty.getSecretId());
+            config.put("secretKey", cosConfigProperty.getSecretKey());
+
+            // 鍒濆鍖� policy
+            Policy policy = new Policy();
+
+            // 璁剧疆鍩熷悕:
+            // 濡傛灉鎮ㄤ娇鐢ㄤ簡鑵捐浜� cvm锛屽彲浠ヨ缃唴閮ㄥ煙鍚�
+            //config.put("host", "sts.internal.tencentcloudapi.com");
+
+            // 涓存椂瀵嗛挜鏈夋晥鏃堕暱锛屽崟浣嶆槸绉掞紝榛樿 1800 绉掞紝鐩墠涓昏处鍙锋渶闀� 2 灏忔椂锛堝嵆 7200 绉掞級锛屽瓙璐﹀彿鏈�闀� 36 灏忔椂锛堝嵆 129600锛夌
+            config.put("durationSeconds", cosConfigProperty.getDurationSeconds());
+            // 鎹㈡垚鎮ㄧ殑 bucket
+            config.put("bucket", cosConfigProperty.getBucket());
+            // 鎹㈡垚 bucket 鎵�鍦ㄥ湴鍖�
+            config.put("region", cosConfigProperty.getRegion());
+
+            // 寮�濮嬫瀯寤轰竴鏉� statement
+            Statement statement = new Statement();
+            // 澹版槑璁剧疆鐨勭粨鏋滄槸鍏佽鎿嶄綔
+            statement.setEffect("allow");
+            /**
+             * 瀵嗛挜鐨勬潈闄愬垪琛ㄣ�傚繀椤诲湪杩欓噷鎸囧畾鏈涓存椂瀵嗛挜鎵�闇�瑕佺殑鏉冮檺銆�
+             * 鏉冮檺鍒楄〃璇峰弬瑙� https://cloud.tencent.com/document/product/436/31923
+             * 瑙勫垯涓� {project}:{interfaceName}
+             * project : 浜у搧缂╁啓  cos鐩稿叧鎺堟潈涓哄�间负cos,鏁版嵁涓囪薄(鏁版嵁澶勭悊)鐩稿叧鎺堟潈鍊间负ci
+             * 鎺堟潈鎵�鏈夋帴鍙g敤*琛ㄧず锛屼緥濡� cos:*,ci:*
+             * 娣诲姞涓�鎵规搷浣滄潈闄� :
+             */
+            statement.addActions(cosConfigProperty.getActions());
+
+            /**
+             * 杩欓噷鏀规垚鍏佽鐨勮矾寰勫墠缂�锛屽彲浠ユ牴鎹嚜宸辩綉绔欑殑鐢ㄦ埛鐧诲綍鎬佸垽鏂厑璁镐笂浼犵殑鍏蜂綋璺緞
+             * 璧勬簮琛ㄨ揪寮忚鍒欏垎瀵硅薄瀛樺偍(cos)鍜屾暟鎹竾璞�(ci)涓ょ
+             * 鏁版嵁澶勭悊銆佸鏍哥浉鍏虫帴鍙i渶瑕佹巿浜坈i璧勬簮鏉冮檺
+             *  cos : qcs::cos:{region}:uid/{appid}:{bucket}/{path}
+             *  ci  : qcs::ci:{region}:uid/{appid}:bucket/{bucket}/{path}
+             * 鍒椾妇鍑犵鍏稿瀷鐨剓path}鎺堟潈鍦烘櫙锛�
+             * 1銆佸厑璁歌闂墍鏈夊璞★細"*"
+             * 2銆佸厑璁歌闂寚瀹氱殑瀵硅薄锛�"a/a1.txt", "b/b1.txt"
+             * 3銆佸厑璁歌闂寚瀹氬墠缂�鐨勫璞★細"a*", "a/*", "b/*"
+             *  濡傛灉濉啓浜嗏��*鈥濓紝灏嗗厑璁哥敤鎴疯闂墍鏈夎祫婧愶紱闄ら潪涓氬姟闇�瑕侊紝鍚﹀垯璇锋寜鐓ф渶灏忔潈闄愬師鍒欐巿浜堢敤鎴风浉搴旂殑璁块棶鏉冮檺鑼冨洿銆�
+             *
+             * 绀轰緥锛氭巿鏉僥xamplebucket-1250000000 bucket鐩綍涓嬬殑鎵�鏈夎祫婧愮粰cos鍜宑i 鎺堟潈涓ゆ潯Resource
+             */
+            statement.addResources(cosConfigProperty.getResources());
+
+            // 鎶婁竴鏉� statement 娣诲姞鍒� policy
+            // 鍙互娣诲姞澶氭潯
+            policy.addStatement(statement);
+            // 灏� Policy 绀轰緥杞寲鎴� String锛屽彲浠ヤ娇鐢ㄤ换浣� json 杞寲鏂瑰紡锛岃繖閲屾槸鏈� SDK 鑷甫鐨勬帹鑽愭柟寮�
+            config.put("policy", Jackson.toJsonPrettyString(policy));
+
+            Response response = CosStsClient.getCredential(config);
+            System.out.println(response.credentials.tmpSecretId);
+            System.out.println(response.credentials.tmpSecretKey);
+            System.out.println(response.credentials.sessionToken);
+
+            CosSTS cosSTS = new CosSTS();
+            cosSTS.setTmpSecretId(response.credentials.tmpSecretId);
+            cosSTS.setTmpSecretKey(response.credentials.tmpSecretKey);
+            cosSTS.setSessionToken(response.credentials.sessionToken);
+            Date now = new Date();
+            cosSTS.setStsStartTime(now.getTime() / 1000);
+            // 棰勭暀30s鐨勮姹傛椂闂达紝闃叉缁欏皬绋嬪簭鐨勭粨鏉熸椂闂磋秴杩囧疄闄呯殑缁撴潫鏃堕棿
+            cosSTS.setStsEndTime(cosSTS.getStsStartTime() + cosConfigProperty.getDurationSeconds() - 30);
+            cosSTS.setBucket(cosConfigProperty.getBucket());
+            cosSTS.setRegion(cosConfigProperty.getRegion());
+            return cosSTS;
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new IllegalArgumentException("get sts error");
+        }
+    }
+
+    /**
+     * 鍒濆鍖朿os瀹㈡埛绔�
+     *
+     * @return COSClient cos瀹㈡埛绔�
+     */
+    public COSClient initClient() {
+        CosSTS sts = this.getSTS();
+        BasicSessionCredentials cred = new BasicSessionCredentials(sts.getTmpSecretId(), sts.getTmpSecretKey(), sts.getSessionToken());
+        // 2 璁剧疆 bucket 鐨勫湴鍩�
+        // clientConfig 涓寘鍚簡璁剧疆 region, https(榛樿 http), 瓒呮椂, 浠g悊绛� set 鏂规硶, 浣跨敤鍙弬瑙佹簮鐮佹垨鑰呭父瑙侀棶棰� Java SDK 閮ㄥ垎
+        Region region = new Region(cosConfigProperty.getRegion()); //COS_REGION 鍙傛暟锛氶厤缃垚瀛樺偍妗� bucket 鐨勫疄闄呭湴鍩燂紝渚嬪 ap-beijing锛屾洿澶� COS 鍦板煙鐨勭畝绉拌鍙傝 https://cloud.tencent.com/document/product/436/6224
+        ClientConfig clientConfig = new ClientConfig(region);
+        // 3 鐢熸垚 cos 瀹㈡埛绔�
+        COSClient cosClient = new COSClient(cred, clientConfig);
+        return cosClient;
+    }
+
+    /**
+     * 鏈�绠�鍗曠殑涓婁紶鏂囦欢
+     *
+     * @param fileInput 鏂囦欢
+     * @param fileInfo 鏂囦欢淇℃伅
+     * @return fileKey 鏂囦欢璺緞锛屾垨鑰呭彨鍞竴鏍囪瘑
+     */
+    public void upload(InputStream fileInput, LmkFile fileInfo) {
+        COSClient cosClient = this.initClient();
+        ObjectMetadata objectMetadata = new ObjectMetadata();
+        objectMetadata.setContentType(fileInfo.getFileType());
+        objectMetadata.setContentLength(fileInfo.getFileSize());
+
+//        objectMetadata.setContentDisposition("attachment;filename=" + URLEncoder.encode(fileInfo.getOriginalFilename(), "UTF-8"));
+        // 鎸囧畾鏂囦欢涓婁紶鍒� COS 涓婄殑璺緞锛屽嵆瀵硅薄閿�備緥濡傚璞¢敭涓� folder/picture.jpg锛屽垯琛ㄧず灏嗘枃浠� picture.jpg 涓婁紶鍒� folder 璺緞涓�
+        PutObjectRequest putObjectRequest = new PutObjectRequest(cosConfigProperty.getBucket(), fileInfo.getFileKey(), fileInput, objectMetadata);
+        PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
+        System.out.println(putObjectResult);
+        cosClient.shutdown();
+    }
+
+    /**
+     * 涓嬭浇鏂囦欢
+     *
+     * @param fileKey 鏂囦欢璺緞锛屾垨鑰呭彨鍞竴鏍囪瘑
+     * @param response
+     */
+    public void download(String fileKey, HttpServletResponse response) {
+        COSClient cosClient = this.initClient();
+        GetObjectRequest getObjectRequest = new GetObjectRequest(cosConfigProperty.getBucket(), fileKey);
+
+        try {
+            // 鑾峰彇COS瀵硅薄
+            COSObject cosObject = cosClient.getObject(getObjectRequest);
+
+            // 鑾峰彇瀵硅薄鍏冩暟鎹�
+            ObjectMetadata metadata = cosObject.getObjectMetadata();
+            String contentType = metadata.getContentType();
+            long contentLength = metadata.getContentLength();
+            String filename = fileKey.substring(fileKey.lastIndexOf('/') + 1);
+
+            // 璁剧疆鍝嶅簲澶�
+            response.setContentType(contentType != null ? contentType : "application/octet-stream");
+            response.setContentLengthLong(contentLength);
+            response.setHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(filename, "UTF-8") + "\"");
+
+            // 鑾峰彇杈撳叆娴佸拰杈撳嚭娴�
+            try (InputStream cosObjectInput = cosObject.getObjectContent();
+                 OutputStream responseOutputStream = response.getOutputStream()) {
+
+                // 浣跨敤缂撳啿鍖轰紶杈撴暟鎹�
+                byte[] buffer = new byte[4096];
+                int bytesRead;
+                while ((bytesRead = cosObjectInput.read(buffer)) != -1) {
+                    responseOutputStream.write(buffer, 0, bytesRead);
+                }
+                responseOutputStream.flush();
+            }
+        } catch (CosServiceException e) {
+            // COS鏈嶅姟寮傚父
+            e.printStackTrace();
+            throw new RuntimeException("瀛樺偍鏈嶅姟寮傚父");
+        } catch (CosClientException e) {
+            // COS瀹㈡埛绔紓甯�
+            e.printStackTrace();
+            throw new RuntimeException("瀛樺偍鏈嶅姟瀹㈡埛绔紓甯�");
+        } catch (IOException e) {
+            // IO寮傚父
+            e.printStackTrace();
+            throw new RuntimeException("鏂囦欢璇诲彇寮傚父");
+        } finally {
+            // 纭繚COS瀹㈡埛绔叧闂�
+            if (cosClient != null) {
+                cosClient.shutdown();
+            }
+        }
+    }
+
+
+    /**
+     * 鑾峰彇鍦ㄧ嚎璁块棶鏂囦欢鍦板潃
+     *
+     * @param fileKey
+     * @return
+     */
+    public String getPreviewUrl(String fileKey) {
+        COSClient cosClient = this.initClient();
+        // 璁剧疆绛惧悕杩囨湡鏃堕棿(鍙��), 鑻ユ湭杩涜璁剧疆鍒欓粯璁や娇鐢� ClientConfig 涓殑绛惧悕杩囨湡鏃堕棿(1灏忔椂)
+        // 杩欓噷璁剧疆绛惧悕鍦ㄥ崐涓皬鏃跺悗杩囨湡
+        Date expirationDate = new Date(System.currentTimeMillis() + cosConfigProperty.getUrlExpireMinute() * 60 * 1000);
+        // 濉啓鏈璇锋眰鐨勫弬鏁帮紝闇�涓庡疄闄呰姹傜浉鍚岋紝鑳藉闃叉鐢ㄦ埛绡℃敼姝ょ鍚嶇殑 HTTP 璇锋眰鐨勫弬鏁�
+        Map<String, String> params = new HashMap<String, String>();
+        // 濉啓鏈璇锋眰鐨勫ご閮紝闇�涓庡疄闄呰姹傜浉鍚岋紝鑳藉闃叉鐢ㄦ埛绡℃敼姝ょ鍚嶇殑 HTTP 璇锋眰鐨勫ご閮�
+        Map<String, String> headers = new HashMap<String, String>();
+        // 璇锋眰鐨� HTTP 鏂规硶锛屼笂浼犺姹傜敤 PUT锛屼笅杞借姹傜敤 GET锛屽垹闄よ姹傜敤 DELETE
+        HttpMethodName method = HttpMethodName.GET;
+        URL url = cosClient.generatePresignedUrl(cosConfigProperty.getBucket(), fileKey, expirationDate, method, headers, params);
+        System.out.println(url.toString());
+        // 纭鏈繘绋嬩笉鍐嶄娇鐢� cosClient 瀹炰緥涔嬪悗锛屽叧闂嵆鍙�
+        cosClient.shutdown();
+        return url.toString();
+    }
+
+
+    /**
+     * 鍒犻櫎鍗曚釜鏂囦欢
+     *
+     * @param fileKey
+     */
+    public void deleteFile(String fileKey) {
+        COSClient cosClient = this.initClient();
+        try {
+            cosClient.deleteObject(cosConfigProperty.getBucket(), fileKey);
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new RuntimeException("鏂囦欢鍒犻櫎澶辫触");
+        } finally {
+            cosClient.shutdown();
+        }
+    }
+
+    /**
+     * 鍒犻櫎澶氫釜鏂囦欢
+     *
+     * @param fileKeys
+     */
+    public void deleteFiles(List<String> fileKeys) {
+        if (CollectionUtils.isEmpty(fileKeys)) {
+            return;
+        }
+        List<DeleteObjectsRequest.KeyVersion> keys = fileKeys.stream().map(key -> new DeleteObjectsRequest.KeyVersion(key)).collect(Collectors.toList());
+        COSClient cosClient = this.initClient();
+        try {
+            DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(cosConfigProperty.getBucket());
+            deleteObjectsRequest.setKeys(keys);
+            cosClient.deleteObjects(deleteObjectsRequest);
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new RuntimeException("鏂囦欢鍒犻櫎澶辫触");
+        } finally {
+            cosClient.shutdown();
+        }
+    }
+
+}
diff --git a/framework/src/main/java/cn/lili/utils/FileUtil.java b/framework/src/main/java/cn/lili/utils/FileUtil.java
new file mode 100644
index 0000000..bd6ef39
--- /dev/null
+++ b/framework/src/main/java/cn/lili/utils/FileUtil.java
@@ -0,0 +1,89 @@
+package cn.lili.utils;
+
+import cn.lili.common.exception.FileFormatNotSupport;
+import cn.lili.modules.lmk.domain.entity.LmkFile;
+import cn.lili.modules.lmk.enums.general.FileTypeEnum;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Random;
+
+/**
+ * @author 29443
+ * @version 1.0
+ * @date 2022/4/25
+ */
+public class FileUtil {
+
+    /**
+     * 鑾峰彇鏂囦欢鍚庣紑
+     *
+     * @param fileName
+     * @return
+     */
+    public static String getSuffix(String fileName) {
+        String suffix = fileName.substring(fileName.lastIndexOf('.') + 1);
+        return suffix;
+    }
+
+    /**
+     * 鑾峰彇璇ユ枃浠朵笂浼犲埌oss鍝釜鐩綍
+     *
+     * @param suffix 鏂囦欢鍚庣紑
+     * @return
+     */
+    public static String getFileType(String suffix) {
+        String fileType = "";
+        for (FileTypeEnum type : FileTypeEnum.values()) {
+            if (type.getSuffixs().contains(suffix)) {
+                fileType = type.getType();
+                return fileType;
+            }
+        }
+        if (StringUtils.isBlank(fileType)) {
+            throw new FileFormatNotSupport("鏂囦欢鏍煎紡" + suffix + "涓嶆敮鎸�", 500);
+        }
+        return fileType;
+    }
+
+    /**
+     * 鑾峰彇鏂囦欢鐨勪俊鎭紝璋冪敤姝ゆ柟娉曢粯璁ゆ櫘閫氫笂浼�
+     *
+     * @param file
+     * @return
+     */
+    public static LmkFile getFileInfo(MultipartFile file) {
+        String originalFilename = file.getOriginalFilename();
+        String random = generateFileKey();
+        String suffix = getSuffix(originalFilename);
+        String fileType = getFileType(suffix);
+        String fileKey = String.format("%s/%s.%s", fileType, random, suffix);
+
+        LmkFile fileInfo = new LmkFile();
+        fileInfo.setFileKey(fileKey);
+        fileInfo.setOriginalFileName(originalFilename);
+        fileInfo.setFileType(file.getContentType());
+        fileInfo.setFileSize(file.getSize());
+
+        return fileInfo;
+    }
+
+
+    /**
+     * 鑾峰彇fileKey
+     *
+     * @return
+     */
+    public static String generateFileKey() {
+        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
+        String no = format.format(new Date());
+        Random random = new Random();
+        for (int i = 0; i < 5; i++) {
+            no += random.nextInt(10);
+        }
+        return no;
+    }
+
+}
diff --git a/framework/src/main/resources/mapper/lmk/LmkFileMapper.xml b/framework/src/main/resources/mapper/lmk/LmkFileMapper.xml
new file mode 100644
index 0000000..8ffe3e7
--- /dev/null
+++ b/framework/src/main/resources/mapper/lmk/LmkFileMapper.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="cn.lili.modules.lmk.mapper.LmkFileMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="cn.lili.modules.lmk.domain.entity.LmkFile">
+        <id column="id" property="id"/>
+        <result column="file_key" property="fileKey" />
+        <result column="file_type" property="fileType" />
+        <result column="file_size" property="fileSize" />
+        <result column="original_filename" property="originalFileName" />
+    </resultMap>
+
+
+
+
+
+
+
+    <select id="getByFileKey" resultMap="BaseResultMap">
+        SELECT
+            LF.file_key,
+            LF.file_type,
+            LF.file_size,
+            LF.original_filename,
+            LF.deleted_flag,
+            LF.id
+        FROM
+            lmk_file LF
+        WHERE
+            LF.file_key = #{flieKey} AND LF.delete_flag = 0
+    </select>
+
+
+</mapper>
diff --git a/framework/src/main/resources/mapper/lmk/VideoMapper.xml b/framework/src/main/resources/mapper/lmk/VideoMapper.xml
new file mode 100644
index 0000000..de55ef3
--- /dev/null
+++ b/framework/src/main/resources/mapper/lmk/VideoMapper.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="cn.lili.modules.lmk.mapper.VideoMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="cn.lili.modules.lmk.domain.vo.VideoVO">
+        <id column="id" property="id"/>
+        <result column="author_id" property="authorId" />
+        <result column="cover_url" property="coverUrl" />
+        <result column="video_file_key" property="videoFileKey" />
+        <result column="video_fit" property="videoFit" />
+        <result column="title" property="title" />
+        <result column="goods_id" property="goodsId" />
+        <result column="goods_view_num" property="goodsViewNum" />
+        <result column="goods_order_num" property="goodsOrderNum" />
+        <result column="recommend" property="recommend" />
+        <result column="status" property="status" />
+        <result column="play_num" property="playNum" />
+        <result column="collect_num" property="collectNum" />
+        <result column="comment_num" property="commentNum" />
+        <result column="weight" property="weight" />
+        <result column="audit_pass_time" property="auditPassTime" />
+    </resultMap>
+
+
+
+
+
+
+
+    <select id="getById" resultMap="BaseResultMap">
+        SELECT
+            LV.author_id,
+            LV.cover_url,
+            LV.video_fit,
+            LV.video_file_key,
+            LV.title,
+            LV.goods_id,
+            LV.goods_view_num,
+            LV.goods_order_num,
+            LV.recommend,
+            LV.status,
+            LV.play_num,
+            LV.collect_num,
+            LV.comment_num,
+            LV.weight,
+            LV.audit_pass_time,
+            LV.id
+        FROM
+            lmk_video LV
+        WHERE
+            LV.id = #{id} AND LV.delete_flag = 0
+    </select>
+
+
+    <select id="getPage" resultMap="BaseResultMap">
+        SELECT
+            LV.author_id,
+            LV.cover_url,
+            LV.video_fit,
+            LV.video_file_key,
+            LV.title,
+            LV.goods_id,
+            LV.goods_view_num,
+            LV.goods_order_num,
+            LV.recommend,
+            LV.status,
+            LV.play_num,
+            LV.collect_num,
+            LV.comment_num,
+            LV.weight,
+            LV.audit_pass_time,
+            LV.id
+        FROM
+            lmk_video LV
+        WHERE
+            LV.delete_flag = 0
+    </select>
+
+</mapper>
diff --git a/framework/src/main/resources/mapper/lmk/VideoTagMapper.xml b/framework/src/main/resources/mapper/lmk/VideoTagMapper.xml
index d63d4f4..86a95c7 100644
--- a/framework/src/main/resources/mapper/lmk/VideoTagMapper.xml
+++ b/framework/src/main/resources/mapper/lmk/VideoTagMapper.xml
@@ -6,6 +6,7 @@
     <resultMap id="BaseResultMap" type="cn.lili.modules.lmk.domain.vo.VideoTagVO">
         <id column="id" property="id"/>
         <result column="tag_name" property="tagName" />
+        <result column="use_num" property="useNum" />
         <result column="create_type" property="createType"/>
         <result column="update_time" property="updateTime" />
     </resultMap>
@@ -19,6 +20,7 @@
     <select id="getById" resultMap="BaseResultMap">
         SELECT
             LVT.tag_name,
+            LVT.use_num,
             LVT.create_type,
             LVT.update_time,
             LVT.id
@@ -32,6 +34,7 @@
     <select id="getPage" resultMap="BaseResultMap">
         SELECT
             LVT.tag_name,
+            LVT.use_num,
             LVT.create_type,
             LVT.update_time,
             LVT.id
diff --git a/framework/src/main/resources/mapper/lmk/VideoTagRefMapper.xml b/framework/src/main/resources/mapper/lmk/VideoTagRefMapper.xml
new file mode 100644
index 0000000..95bafd6
--- /dev/null
+++ b/framework/src/main/resources/mapper/lmk/VideoTagRefMapper.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="cn.lili.modules.lmk.mapper.VideoTagRefMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="cn.lili.modules.lmk.domain.entity.VideoTagRef">
+        <id column="id" property="id"/>
+        <result column="video_id" property="videoId" />
+        <result column="video_tag_id" property="videoTagId" />
+    </resultMap>
+
+
+
+
+</mapper>
diff --git a/manager-api/src/main/java/cn/lili/controller/lmk/VideoController.java b/manager-api/src/main/java/cn/lili/controller/lmk/VideoController.java
new file mode 100644
index 0000000..48a84ca
--- /dev/null
+++ b/manager-api/src/main/java/cn/lili/controller/lmk/VideoController.java
@@ -0,0 +1,76 @@
+package cn.lili.controller.lmk;
+
+import cn.lili.group.Update;
+import cn.lili.group.Add;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import lombok.RequiredArgsConstructor;
+import java.util.List;
+import org.springframework.validation.annotation.Validated;
+import javax.validation.constraints.NotEmpty;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import cn.lili.modules.lmk.service.VideoService;
+import cn.lili.base.Result;
+import cn.lili.modules.lmk.domain.form.VideoForm;
+import cn.lili.modules.lmk.domain.query.VideoQuery;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 瑙嗛鍐呭 鍓嶇鎺у埗鍣�
+ *
+ * @author xp
+ * @since 2025-05-16
+ */
+@Validated
+@RequiredArgsConstructor
+@Api(value = "瑙嗛鍐呭", tags = "瑙嗛鍐呭绠$悊")
+@RestController
+@RequestMapping("/manager/lmk/video")
+public class VideoController {
+
+    private final VideoService videoService;
+
+    @PostMapping
+    @ApiOperation(value = "娣诲姞", notes = "娣诲姞")
+    public Result add(@RequestBody @Validated(Add.class) VideoForm form) {
+        return videoService.add(form);
+    }
+
+    @PutMapping
+    @ApiOperation(value = "淇敼", notes = "淇敼")
+    public Result update(@RequestBody @Validated(Update.class) VideoForm form) {
+        return videoService.update(form);
+    }
+
+    @DeleteMapping("/{id}")
+    @ApiOperation(value = "ID鍒犻櫎", notes = "ID鍒犻櫎")
+    public Result removeById(@PathVariable("id") String id) {
+        return videoService.removeById(id);
+    }
+
+    @DeleteMapping("/batch")
+    @ApiOperation(value = "鎵归噺鍒犻櫎", notes = "鎵归噺鍒犻櫎")
+    public Result remove(@RequestBody @NotEmpty(message = "璇烽�夋嫨鏁版嵁") List<String> ids) {
+        return videoService.remove(ids);
+    }
+
+    @GetMapping("/page")
+    @ApiOperation(value = "鍒嗛〉", notes = "鍒嗛〉")
+    public Result page(VideoQuery query) {
+        return videoService.page(query);
+    }
+
+    @GetMapping("/{id}")
+    @ApiOperation(value = "璇︽儏", notes = "璇︽儏")
+    public Result detail(@PathVariable("id") Integer id) {
+        return videoService.detail(id);
+    }
+
+    @GetMapping("/list")
+    @ApiOperation(value = "鍒楄〃", notes = "鍒楄〃")
+    public Result list() {
+        return videoService.all();
+    }
+}
diff --git a/pom.xml b/pom.xml
index af61ff3..3727158 100644
--- a/pom.xml
+++ b/pom.xml
@@ -65,6 +65,7 @@
         <cos.version>5.6.97</cos.version>
         <tencentcloud.version>3.1.693</tencentcloud.version>
         <kuaidi100-api.version>1.0.11</kuaidi100-api.version>
+        <tx-cos.version>5.6.227</tx-cos.version>
     </properties>
 
     <modules>
@@ -138,4 +139,4 @@
             </snapshots>
         </repository>
     </repositories>
-</project>
\ No newline at end of file
+</project>

--
Gitblit v1.8.0