Compare commits
10 Commits
b20f30f91b
...
05ea918ee1
| Author | SHA1 | Date | |
|---|---|---|---|
| 05ea918ee1 | |||
| 50f1bdba38 | |||
| 74fa304cd9 | |||
| 9d352f40a0 | |||
| 674188f471 | |||
| 62ca1730b9 | |||
| 0d27d1a072 | |||
| d74d8b22c6 | |||
| 489131a04b | |||
| 43ac037f5b |
@@ -149,6 +149,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { useAppStore } from '../../stores/app.js'
|
import { useAppStore } from '../../stores/app.js'
|
||||||
|
import { toggleFavoriteScript } from '../../services/epicScript.js'
|
||||||
|
|
||||||
const store = useAppStore()
|
const store = useAppStore()
|
||||||
const activeType = ref('long')
|
const activeType = ref('long')
|
||||||
@@ -316,15 +317,34 @@ const toggleScriptMenu = (script) => {
|
|||||||
activeMenuId.value = activeMenuId.value === id ? '' : id
|
activeMenuId.value = activeMenuId.value === id ? '' : id
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleFavorite = (script) => {
|
const toggleFavorite = async (script) => {
|
||||||
const favorite = isFavorite(script)
|
const wasFav = isFavorite(script)
|
||||||
|
// 乐观更新:先改本地缓存
|
||||||
const next = { ...localFavorites.value }
|
const next = { ...localFavorites.value }
|
||||||
if (favorite) delete next[String(script.id)]
|
if (wasFav) {
|
||||||
else next[String(script.id)] = true
|
delete next[String(script.id)]
|
||||||
|
} else {
|
||||||
|
next[String(script.id)] = true
|
||||||
|
}
|
||||||
localFavorites.value = next
|
localFavorites.value = next
|
||||||
uni.setStorageSync('script_favorites', next)
|
uni.setStorageSync('script_favorites', next)
|
||||||
closeScriptMenu()
|
closeScriptMenu()
|
||||||
uni.showToast({ title: favorite ? '已取消收藏' : '已收藏', icon: 'success' })
|
|
||||||
|
try {
|
||||||
|
const result = await toggleFavoriteScript(script.id)
|
||||||
|
uni.showToast({ title: result.isFavorited ? '已收藏' : '已取消收藏', icon: 'success' })
|
||||||
|
} catch (error) {
|
||||||
|
// 回滚乐观更新
|
||||||
|
const restored = { ...localFavorites.value }
|
||||||
|
if (wasFav) {
|
||||||
|
restored[String(script.id)] = true
|
||||||
|
} else {
|
||||||
|
delete restored[String(script.id)]
|
||||||
|
}
|
||||||
|
localFavorites.value = restored
|
||||||
|
uni.setStorageSync('script_favorites', restored)
|
||||||
|
uni.showToast({ title: error?.message || '操作失败', icon: 'none' })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const continueScript = (script) => {
|
const continueScript = (script) => {
|
||||||
|
|||||||
@@ -198,6 +198,39 @@ export const transformListToFrontend = (backendList) => {
|
|||||||
return backendList.map(transformToFrontendFormat)
|
return backendList.map(transformToFrontendFormat)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 切换剧本收藏状态(收藏/取消收藏)
|
||||||
|
* @param {string} scriptId 剧本ID
|
||||||
|
* @returns {Promise<{success: boolean, isFavorited: boolean}>}
|
||||||
|
*/
|
||||||
|
export const toggleFavoriteScript = async (scriptId) => {
|
||||||
|
const res = await post('/epicScript/favorite/toggle', { scriptId })
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
isFavorited: res.data?.isFavorited ?? false,
|
||||||
|
favoriteTime: res.data?.favoriteTime ?? null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取收藏剧本列表
|
||||||
|
* @param {number} current 当前页
|
||||||
|
* @param {number} size 每页大小
|
||||||
|
*/
|
||||||
|
export const getFavoriteScriptPage = async (current = 1, size = 10) => {
|
||||||
|
return get('/epicScript/favorite/page', { current, size })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查剧本是否已收藏
|
||||||
|
* @param {string} scriptId 剧本ID
|
||||||
|
* @returns {Promise<boolean>}
|
||||||
|
*/
|
||||||
|
export const checkFavoriteScript = async (scriptId) => {
|
||||||
|
const res = await get('/epicScript/favorite/check', { scriptId })
|
||||||
|
return res.data?.isFavorited ?? false
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
getScriptList,
|
getScriptList,
|
||||||
getScriptPage,
|
getScriptPage,
|
||||||
@@ -212,5 +245,8 @@ export default {
|
|||||||
buildCharacterInfo,
|
buildCharacterInfo,
|
||||||
buildLifeEventsSummary,
|
buildLifeEventsSummary,
|
||||||
transformToFrontendFormat,
|
transformToFrontendFormat,
|
||||||
transformListToFrontend
|
transformListToFrontend,
|
||||||
|
toggleFavoriteScript,
|
||||||
|
getFavoriteScriptPage,
|
||||||
|
checkFavoriteScript,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,13 +8,16 @@ import com.emotion.dto.request.EpicScriptInspirationRequest;
|
|||||||
import com.emotion.dto.request.EpicScriptPageRequest;
|
import com.emotion.dto.request.EpicScriptPageRequest;
|
||||||
import com.emotion.dto.request.EpicScriptUpdateRequest;
|
import com.emotion.dto.request.EpicScriptUpdateRequest;
|
||||||
import com.emotion.dto.request.SwitchVersionRequest;
|
import com.emotion.dto.request.SwitchVersionRequest;
|
||||||
|
import com.emotion.dto.request.ScriptFavoriteToggleRequest;
|
||||||
import com.emotion.dto.response.EpicScriptCreateWithDialogueResponse;
|
import com.emotion.dto.response.EpicScriptCreateWithDialogueResponse;
|
||||||
import com.emotion.dto.response.EpicScriptInspirationResponse;
|
import com.emotion.dto.response.EpicScriptInspirationResponse;
|
||||||
import com.emotion.dto.response.EpicScriptResponse;
|
import com.emotion.dto.response.EpicScriptResponse;
|
||||||
import com.emotion.dto.response.InspirationSuggestionResponse;
|
import com.emotion.dto.response.InspirationSuggestionResponse;
|
||||||
import com.emotion.service.EpicScriptDialogueService;
|
import com.emotion.service.EpicScriptDialogueService;
|
||||||
|
import com.emotion.dto.response.ScriptFavoriteResponse;
|
||||||
import com.emotion.service.EpicScriptService;
|
import com.emotion.service.EpicScriptService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import com.emotion.service.ScriptFavoriteService;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -41,6 +44,9 @@ public class EpicScriptController {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private EpicScriptDialogueService epicScriptDialogueService;
|
private EpicScriptDialogueService epicScriptDialogueService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ScriptFavoriteService scriptFavoriteService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分页查询当前用户的爽文剧本
|
* 分页查询当前用户的爽文剧本
|
||||||
*/
|
*/
|
||||||
@@ -172,4 +178,31 @@ public class EpicScriptController {
|
|||||||
}
|
}
|
||||||
return Result.success();
|
return Result.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== 剧本收藏 ====================
|
||||||
|
|
||||||
|
@Operation(summary = "切换收藏", description = "收藏或取消收藏指定剧本。")
|
||||||
|
@PostMapping(value = "/favorite/toggle")
|
||||||
|
public Result<ScriptFavoriteResponse> toggleFavorite(
|
||||||
|
@Valid @RequestBody ScriptFavoriteToggleRequest request) {
|
||||||
|
return Result.success(scriptFavoriteService.toggleFavorite(request.getScriptId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "分页查询收藏", description = "分页查询当前用户收藏的剧本列表。")
|
||||||
|
@GetMapping(value = "/favorite/page")
|
||||||
|
public Result<PageResult<EpicScriptResponse>> getFavoritePage(
|
||||||
|
@RequestParam(defaultValue = "1") long current,
|
||||||
|
@RequestParam(defaultValue = "10") long size) {
|
||||||
|
return Result.success(scriptFavoriteService.getFavoritePage(current, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "检查收藏状态", description = "检查指定剧本是否已被当前用户收藏。")
|
||||||
|
@GetMapping(value = "/favorite/check")
|
||||||
|
public Result<ScriptFavoriteResponse> checkFavorite(@RequestParam String scriptId) {
|
||||||
|
boolean favorited = scriptFavoriteService.isFavorited(scriptId);
|
||||||
|
ScriptFavoriteResponse r = new ScriptFavoriteResponse();
|
||||||
|
r.setScriptId(scriptId);
|
||||||
|
r.setIsFavorited(favorited);
|
||||||
|
return Result.success(r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.emotion.dto.request;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 剧本收藏切换请求
|
||||||
|
*
|
||||||
|
* @author huazhongmin
|
||||||
|
* @date 2026-07-19
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ScriptFavoriteToggleRequest {
|
||||||
|
|
||||||
|
@NotBlank(message = "剧本ID不能为空")
|
||||||
|
private String scriptId;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.emotion.dto.response;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 剧本收藏状态响应
|
||||||
|
*
|
||||||
|
* @author huazhongmin
|
||||||
|
* @date 2026-07-19
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ScriptFavoriteResponse {
|
||||||
|
|
||||||
|
private String scriptId;
|
||||||
|
|
||||||
|
private Boolean isFavorited;
|
||||||
|
|
||||||
|
private String favoriteTime;
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.emotion.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.emotion.common.BaseEntity;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 剧本收藏关联实体
|
||||||
|
*
|
||||||
|
* @author huazhongmin
|
||||||
|
* @date 2026-07-19
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@SuperBuilder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@TableName("t_script_favorite")
|
||||||
|
public class ScriptFavorite extends BaseEntity {
|
||||||
|
|
||||||
|
@TableField("user_id")
|
||||||
|
private String userId;
|
||||||
|
|
||||||
|
@TableField("script_id")
|
||||||
|
private String scriptId;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.emotion.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.emotion.entity.ScriptFavorite;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 剧本收藏Mapper接口
|
||||||
|
*
|
||||||
|
* @author huazhongmin
|
||||||
|
* @date 2026-07-19
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface ScriptFavoriteMapper extends BaseMapper<ScriptFavorite> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.emotion.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.emotion.common.PageResult;
|
||||||
|
import com.emotion.dto.response.EpicScriptResponse;
|
||||||
|
import com.emotion.dto.response.ScriptFavoriteResponse;
|
||||||
|
import com.emotion.entity.ScriptFavorite;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 剧本收藏服务接口
|
||||||
|
*
|
||||||
|
* @author huazhongmin
|
||||||
|
* @date 2026-07-19
|
||||||
|
*/
|
||||||
|
public interface ScriptFavoriteService extends IService<ScriptFavorite> {
|
||||||
|
|
||||||
|
ScriptFavoriteResponse toggleFavorite(String scriptId);
|
||||||
|
|
||||||
|
PageResult<EpicScriptResponse> getFavoritePage(long current, long size);
|
||||||
|
|
||||||
|
Set<String> getFavoritedScriptIds(Set<String> scriptIds);
|
||||||
|
|
||||||
|
boolean isFavorited(String scriptId);
|
||||||
|
|
||||||
|
long getFavoriteCount();
|
||||||
|
}
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
package com.emotion.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.emotion.common.PageResult;
|
||||||
|
import com.emotion.dto.response.EpicScriptResponse;
|
||||||
|
import com.emotion.dto.response.ScriptFavoriteResponse;
|
||||||
|
import com.emotion.entity.ScriptFavorite;
|
||||||
|
import com.emotion.mapper.ScriptFavoriteMapper;
|
||||||
|
import com.emotion.service.EpicScriptService;
|
||||||
|
import com.emotion.service.ScriptFavoriteService;
|
||||||
|
import com.emotion.util.UserContextHolder;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 剧本收藏服务实现
|
||||||
|
*
|
||||||
|
* @author huazhongmin
|
||||||
|
* @date 2026-07-19
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class ScriptFavoriteServiceImpl extends ServiceImpl<ScriptFavoriteMapper, ScriptFavorite>
|
||||||
|
implements ScriptFavoriteService {
|
||||||
|
|
||||||
|
private static final DateTimeFormatter FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private EpicScriptService epicScriptService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public ScriptFavoriteResponse toggleFavorite(String scriptId) {
|
||||||
|
String userId = UserContextHolder.getCurrentUserId();
|
||||||
|
ScriptFavoriteResponse r = new ScriptFavoriteResponse();
|
||||||
|
r.setScriptId(scriptId);
|
||||||
|
|
||||||
|
if (!StringUtils.hasText(userId)) {
|
||||||
|
r.setIsFavorited(false);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
LambdaQueryWrapper<ScriptFavorite> w = new LambdaQueryWrapper<>();
|
||||||
|
w.eq(ScriptFavorite::getUserId, userId)
|
||||||
|
.eq(ScriptFavorite::getScriptId, scriptId)
|
||||||
|
.eq(ScriptFavorite::getIsDeleted, 0);
|
||||||
|
|
||||||
|
ScriptFavorite existing = this.getOne(w);
|
||||||
|
if (existing != null) {
|
||||||
|
this.removeById(existing.getId());
|
||||||
|
r.setIsFavorited(false);
|
||||||
|
} else {
|
||||||
|
ScriptFavorite fav = new ScriptFavorite();
|
||||||
|
fav.setUserId(userId);
|
||||||
|
fav.setScriptId(scriptId);
|
||||||
|
this.save(fav);
|
||||||
|
r.setIsFavorited(true);
|
||||||
|
if (fav.getCreateTime() != null) {
|
||||||
|
r.setFavoriteTime(fav.getCreateTime().format(FMT));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageResult<EpicScriptResponse> getFavoritePage(long current, long size) {
|
||||||
|
String userId = UserContextHolder.getCurrentUserId();
|
||||||
|
if (!StringUtils.hasText(userId)) {
|
||||||
|
return new PageResult<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
LambdaQueryWrapper<ScriptFavorite> w = new LambdaQueryWrapper<>();
|
||||||
|
w.eq(ScriptFavorite::getUserId, userId)
|
||||||
|
.eq(ScriptFavorite::getIsDeleted, 0)
|
||||||
|
.orderByDesc(ScriptFavorite::getCreateTime);
|
||||||
|
|
||||||
|
Page<ScriptFavorite> page = new Page<>(current, size);
|
||||||
|
Page<ScriptFavorite> result = this.page(page, w);
|
||||||
|
|
||||||
|
List<EpicScriptResponse> records = result.getRecords().stream()
|
||||||
|
.map(ScriptFavorite::getScriptId)
|
||||||
|
.map(epicScriptService::getScriptById)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
PageResult<EpicScriptResponse> pr = new PageResult<>();
|
||||||
|
pr.setCurrent(result.getCurrent());
|
||||||
|
pr.setSize(result.getSize());
|
||||||
|
pr.setTotal(result.getTotal());
|
||||||
|
pr.setPages(result.getPages());
|
||||||
|
pr.setRecords(records);
|
||||||
|
return pr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getFavoritedScriptIds(Set<String> scriptIds) {
|
||||||
|
String userId = UserContextHolder.getCurrentUserId();
|
||||||
|
if (!StringUtils.hasText(userId) || scriptIds == null || scriptIds.isEmpty()) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
LambdaQueryWrapper<ScriptFavorite> w = new LambdaQueryWrapper<>();
|
||||||
|
w.eq(ScriptFavorite::getUserId, userId)
|
||||||
|
.in(ScriptFavorite::getScriptId, scriptIds)
|
||||||
|
.eq(ScriptFavorite::getIsDeleted, 0);
|
||||||
|
|
||||||
|
return this.list(w).stream()
|
||||||
|
.map(ScriptFavorite::getScriptId)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFavorited(String scriptId) {
|
||||||
|
String userId = UserContextHolder.getCurrentUserId();
|
||||||
|
if (!StringUtils.hasText(userId) || !StringUtils.hasText(scriptId)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LambdaQueryWrapper<ScriptFavorite> w = new LambdaQueryWrapper<>();
|
||||||
|
w.eq(ScriptFavorite::getUserId, userId)
|
||||||
|
.eq(ScriptFavorite::getScriptId, scriptId)
|
||||||
|
.eq(ScriptFavorite::getIsDeleted, 0);
|
||||||
|
|
||||||
|
return this.count(w) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getFavoriteCount() {
|
||||||
|
String userId = UserContextHolder.getCurrentUserId();
|
||||||
|
if (!StringUtils.hasText(userId)) {
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
LambdaQueryWrapper<ScriptFavorite> w = new LambdaQueryWrapper<>();
|
||||||
|
w.eq(ScriptFavorite::getUserId, userId)
|
||||||
|
.eq(ScriptFavorite::getIsDeleted, 0);
|
||||||
|
|
||||||
|
return this.count(w);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
-- 剧本收藏关联表
|
||||||
|
-- 存储用户对剧本的收藏关系,多对多关联
|
||||||
|
CREATE TABLE t_script_favorite (
|
||||||
|
id VARCHAR(64) NOT NULL PRIMARY KEY COMMENT '主键ID',
|
||||||
|
user_id VARCHAR(64) NOT NULL COMMENT '用户ID,关联t_user.id',
|
||||||
|
script_id VARCHAR(64) NOT NULL COMMENT '剧本ID,关联t_epic_script.id',
|
||||||
|
create_by VARCHAR(64) DEFAULT NULL COMMENT '创建人',
|
||||||
|
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '收藏时间',
|
||||||
|
update_by VARCHAR(64) DEFAULT NULL COMMENT '更新人',
|
||||||
|
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
is_deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除: 0-未删除, 1-已删除',
|
||||||
|
remarks VARCHAR(500) DEFAULT '' COMMENT '备注(预留,可存收藏夹名或备注)',
|
||||||
|
|
||||||
|
UNIQUE KEY uk_user_script (user_id, script_id),
|
||||||
|
KEY idx_user_id (user_id),
|
||||||
|
KEY idx_script_id (script_id)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='剧本收藏关联表';
|
||||||
Reference in New Issue
Block a user