更新:图书搜索功能;听书实时显示对应文字;书籍评论功能完善;

This commit is contained in:
2025-11-12 09:02:30 +08:00
parent 9fcc1b8549
commit 1da75a59f2
21 changed files with 484 additions and 828 deletions

View File

@@ -15,15 +15,8 @@
<style lang="scss">
@import "@/style/tailwind.css";
@import "@/style/ui.scss";
/* 覆盖 Tailwind 的默认 block 样式 */
img, svg, video, canvas, audio, iframe, embed, object {
display: inline-block;
}
.container {
padding: 15px;
}
button {
line-height: inherit;
}
</style>

View File

@@ -8,6 +8,7 @@ export const ENV = process.env.NODE_ENV || 'development';
const BASE_URL_MAP = {
development: {
MAIN: 'http://192.168.110.100:9300/pb/',
// MAIN: 'https://global.nuttyreading.com/',
// PAYMENT: 'https://dev-pay.example.com', // 暂时用不到
// CDN: 'https://cdn-dev.example.com', // 暂时用不到
},

View File

@@ -200,5 +200,17 @@ export const bookApi = {
method: 'POST',
data: { bookId }
})
},
/**
* 获取听书章节内容(带音频时间点)
* @param chapterId 章节ID
*/
getChapterContentListen(chapterId: number) {
return client.request<IApiResponse<{ bookChapterContents: any[] }>>({
url: 'bookAbroad/home/getBookChapterContentListen',
method: 'POST',
data: { chapterId }
})
}
}

View File

@@ -97,7 +97,7 @@ export const homeApi = {
limit: number,
}) {
return client.request<ISearchResponse>({
url: 'book/shopproduct/selectList',
url: 'bookAbroad/home/searchBook',
method: 'POST',
data
})

View File

@@ -0,0 +1,94 @@
**简要描述:**
- 表情插件
版本 v1.0.0
qq表情
基于colorui 通过 vue 实现
表情放在static下的 bkhumor-emoji 目录下。
使用方法请参考下方的 【模板示例】。
**注意:手机上运行需要将表情图片放到自己服务器。**
[![示例图](http://xinghuo.webdog.club/o_1gti10ds01515kqi1vip1can1cvfl.png)]
[![示例图2](http://xinghuo.webdog.club/o_1gti120uh15lm1bod1n38ejldsmq.png)]
```javascript
模板示例
<view class="flex">
<view class="flex-sub padding-left-xs" style="align-self: center;">
<input type="text" @focus="InputFocus" @blur="InputBlur" :value="inputValue" placeholder-style="font-size:24rpx;color:#aaaaaa;" placeholder="请输入您要发送的内容" maxlength="300"></input>
</view>
<view class="text-center" style="width: 80rpx; font-size: 50rpx;">
<text :class="emojiIcon" @tap="showEmj"></text>
</view>
<button class="cu-btn bg-gradual-blue shadow-blur">发送</button>
</view>
<emotion @emotion="handleEmj" :height="200" v-if="isShowEmj"></emotion>
</view>
JS部分
import emotion from '@/components/bkhumor-emojiplus/bkhumor-emojiplus.vue';
export default {
data() {
return {
title: 'Hello',
isShowEmj: false,
emojiIcon:'cuIcon-emoji',
inputValue:''
}
},
onLoad() {
},
components:{
emotion
},
methods: {
handleEmj(i) {
if(i == '[em_98]') {
//匹配最后一个表情符号并删除。
this.inputValue = this.inputValue.replace(/(\[[^\]]+\]|[\s\S])$/, '');
} else {
this.inputValue += i;
}
},
showEmj() {
let bool = !this.isShowEmj;
if(bool) {
this.emojiIcon = 'cuIcon-keyboard';
} else {
this.emojiIcon = 'cuIcon-emoji';
}
this.isShowEmj = bool;
this.$emit('show')
},
InputBlur(e){
},
InputFocus(e){
this.isShowEmj = false;
this.$emit('foc')
},
}
}
```
**注意事项**
【1】请在入口页面根目录下的App.vue引入以下css:
/*每个页面公共css */
@import "bkhumor-emojiplus/components/colorui/main.css";
@import "bkhumor-emojiplus/components/colorui/icon.css"
【2】为了保证图片生效可控建议将components/bkhumor-emoji/index.vue中的图片路径替换为自己服务器的图片路径。
- 更多详细内容请参看demo有疑问可留言
欢迎使用ShowDoc

View File

@@ -0,0 +1,64 @@
const emojiList = [
{"url":"0@2x.gif","alt":"[惊讶]"},{"url":"1@2x.gif","alt":"[撇嘴]"},{"url":"2@2x.gif","alt":"[色]"},{"url":"3@2x.gif","alt":"[啊这]"},{"url":"4@2x.gif","alt":"[得意]"},{"url":"5@2x.gif","alt":"[流泪]"},{"url":"6@2x.gif","alt":"[害羞]"},
{"url":"7@2x.gif","alt":"[闭嘴]"},{"url":"8@2x.gif","alt":"[睡]"},{"url":"9@2x.gif","alt":"[大哭]"},{"url":"10@2x.gif","alt":"[尴尬]"},{"url":"11@2x.gif","alt":"[发怒]"},{"url":"12@2x.gif","alt":"[调皮]"},{"url":"13@2x.gif","alt":"[呲牙]"},
{"url":"14@2x.gif","alt":"[微笑]"},{"url":"15@2x.gif","alt":"[难过]"},{"url":"16@2x.gif","alt":"[酷]"},{"url":"18@2x.gif","alt":"[抓狂]"},{"url":"19@2x.gif","alt":"[吐]"},{"url":"20@2x.gif","alt":"[偷笑]"},{"url":"21@2x.gif","alt":"[可爱]"},
{"url":"22@2x.gif","alt":"[白眼]"},{"url":"23@2x.gif","alt":"[傲慢]"},{"url":"24@2x.gif","alt":"[饥饿]"},{"url":"25@2x.gif","alt":"[困]"},{"url":"26@2x.gif","alt":"[惊恐]"},{"url":"27@2x.gif","alt":"[流汗]"},{"url":"28@2x.gif","alt":"[憨笑]"},
{"url":"29@2x.gif","alt":"[悠闲]"},{"url":"30@2x.gif","alt":"[奋斗]"},{"url":"31@2x.gif","alt":"[咒骂]"},{"url":"32@2x.gif","alt":"[疑问]"},{"url":"33@2x.gif","alt":"[嘘]"},{"url":"34@2x.gif","alt":"[晕]"},{"url":"35@2x.gif","alt":"[折磨]"},
{"url":"36@2x.gif","alt":"[衰]"},{"url":"37@2x.gif","alt":"[骷髅]"},{"url":"38@2x.gif","alt":"[敲打]"},{"url":"39@2x.gif","alt":"[再见]"},{"url":"46@2x.gif","alt":"[猪头]"},{"url":"49@2x.gif","alt":"[抱抱]"},{"url":"53@2x.gif","alt":"[生日]"},
{"url":"54@2x.gif","alt":"[闪电]"},{"url":"55@2x.gif","alt":"[炸弹]"},{"url":"56@2x.gif","alt":"[刀]"},{"url":"57@2x.gif","alt":"[足球]"},{"url":"59@2x.gif","alt":"[便便]"},{"url":"60@2x.gif","alt":"[咖啡]"},{"url":"61@2x.gif","alt":"[饭]"},
{"url":"62@2x.gif","alt":"[药]"},{"url":"63@2x.gif","alt":"[玫瑰]"},{"url":"64@2x.gif","alt":"[凋谢]"},{"url":"66@2x.gif","alt":"[爱心]"},{"url":"67@2x.gif","alt":"[心碎]"},{"url":"69@2x.gif","alt":"[礼物]"},{"url":"72@2x.gif","alt":"[信封]"},
{"url":"74@2x.gif","alt":"[太阳]"},{"url":"75@2x.gif","alt":"[月亮]"},{"url":"76@2x.gif","alt":"[赞]"},{"url":"77@2x.gif","alt":"[踩]"},{"url":"78@2x.gif","alt":"[握手]"},{"url":"79@2x.gif","alt":"[胜利]"},{"url":"89@2x.gif","alt":"[西瓜]"},
{"url":"90@2x.gif","alt":"[下雨]"},{"url":"91@2x.gif","alt":"[多云]"},{"url":"96@2x.gif","alt":"[冷汗]"},{"url":"97@2x.gif","alt":"[擦汗]"},{"url":"98@2x.gif","alt":"[抠鼻]"},{"url":"99@2x.gif","alt":"[鼓掌]"},{"url":"100@2x.gif","alt":"[嗅大了]"},
{"url":"101@2x.gif","alt":"[坏笑]"},{"url":"102@2x.gif","alt":"[右哼哼]"},{"url":"103@2x.gif","alt":"[左哼哼]"},{"url":"104@2x.gif","alt":"[哈欠]"},{"url":"105@2x.gif","alt":"[鄙视]"},{"url":"106@2x.gif","alt":"[委屈]"},{"url":"107@2x.gif","alt":"[快哭了]"},
{"url":"108@2x.gif","alt":"[阴险]"},{"url":"109@2x.gif","alt":"[亲亲]"},{"url":"110@2x.gif","alt":"[吓]"},{"url":"111@2x.gif","alt":"[可怜]"},{"url":"112@2x.gif","alt":"[菜刀]"},{"url":"113@2x.gif","alt":"[啤酒]"},{"url":"114@2x.gif","alt":"[篮球]"},
{"url":"115@2x.gif","alt":"[乒乓]"},{"url":"116@2x.gif","alt":"[示爱]"},{"url":"117@2x.gif","alt":"[瓢虫]"},{"url":"118@2x.gif","alt":"[抱拳]"},{"url":"119@2x.gif","alt":"[勾引]"},{"url":"120@2x.gif","alt":"[拳头]"},{"url":"121@2x.gif","alt":"[差劲]"},
{"url":"122@2x.gif","alt":"[爱你]"},{"url":"123@2x.gif","alt":"[NO]"},{"url":"124@2x.gif","alt":"[OK]"},{"url":"136@2x.gif","alt":"[双喜]"},{"url":"137@2x.gif","alt":"[鞭炮]"},{"url":"138@2x.gif","alt":"[灯笼]"},{"url":"139@2x.gif","alt":"[麻将]"},
{"url":"140@2x.gif","alt":"[唱歌]"},{"url":"141@2x.gif","alt":"[包包]"},{"url":"142@2x.gif","alt":"[信]"},{"url":"143@2x.gif","alt":"[象棋]"},{"url":"144@2x.gif","alt":"[礼物]"},{"url":"145@2x.gif","alt":"[祈祷]"},{"url":"146@2x.gif","alt":"[爆筋]"},
{"url":"147@2x.gif","alt":"[棒棒糖]"},{"url":"148@2x.gif","alt":"[喝奶]"},{"url":"149@2x.gif","alt":"[吃面]"},{"url":"150@2x.gif","alt":"[香蕉]"},{"url":"151@2x.gif","alt":"[飞机]"},{"url":"152@2x.gif","alt":"[汽车]"},{"url":"153@2x.gif","alt":"[高铁]"},
{"url":"154@2x.gif","alt":"[动车]"},{"url":"155@2x.gif","alt":"[动车头]"},{"url":"156@2x.gif","alt":"[多云]"},{"url":"157@2x.gif","alt":"[下雨]"},{"url":"158@2x.gif","alt":"[钞票]"},{"url":"159@2x.gif","alt":"[熊猫]"},{"url":"160@2x.gif","alt":"[电灯泡]"},
{"url":"161@2x.gif","alt":"[七彩]"},{"url":"162@2x.gif","alt":"[闹钟]"},{"url":"163@2x.gif","alt":"[雨伞]"},{"url":"164@2x.gif","alt":"[气球]"},{"url":"165@2x.gif","alt":"[钻戒]"},{"url":"166@2x.gif","alt":"[座椅]"},{"url":"167@2x.gif","alt":"[纸巾]"},
{"url":"168@2x.gif","alt":"[药丸]"},{"url":"169@2x.gif","alt":"[手枪]"},{"url":"170@2x.gif","alt":"[青蛙]"},{"url":"171@2x.gif","alt":"[热汤]"},{"url":"172@2x.gif","alt":"[眨眼睛]"},{"url":"173@2x.gif","alt":"[泪奔]"},{"url":"174@2x.gif","alt":"[无奈]"},
{"url":"175@2x.gif","alt":"[卖萌]"},{"url":"176@2x.gif","alt":"[小纠结]"},{"url":"177@2x.gif","alt":"[喷血]"},{"url":"178@2x.gif","alt":"[斜眼笑]"},{"url":"179@2x.gif","alt":"[高傲]"},{"url":"180@2x.gif","alt":"[惊喜]"},{"url":"181@2x.gif","alt":"[骚扰]"},
{"url":"182@2x.gif","alt":"[笑哭]"},{"url":"183@2x.gif","alt":"[我最美]"},{"url":"184@2x.gif","alt":"[河蟹]"},{"url":"185@2x.gif","alt":"[羊驼]"},{"url":"186@2x.gif","alt":"[板栗]"},{"url":"187@2x.gif","alt":"[幽灵]"},{"url":"188@2x.gif","alt":"[鸡蛋]"},
{"url":"189@2x.gif","alt":"[魔方]"},{"url":"190@2x.gif","alt":"[转花圈]"},{"url":"191@2x.gif","alt":"[搓澡]"},{"url":"192@2x.gif","alt":"[红包]"},{"url":"200@2x.gif","alt":"[拜托]"},{"url":"201@2x.gif","alt":"[点赞]"},{"url":"202@2x.gif","alt":"[无聊]"},
{"url":"203@2x.gif","alt":"[托脸]"},{"url":"204@2x.gif","alt":"[吃]"},{"url":"205@2x.gif","alt":"[送花]"},{"url":"206@2x.gif","alt":"[害怕]"},{"url":"207@2x.gif","alt":"[花痴]"},{"url":"208@2x.gif","alt":"[小样儿]"},{"url":"210@2x.gif","alt":"[飙泪]"},
{"url":"211@2x.gif","alt":"[我不看]"},{"url":"212@2x.gif","alt":"[托腮]"},{"url":"245@2x.gif","alt":"[加油必胜]"},{"url":"246@2x.gif","alt":"[抱抱]"},{"url":"247@2x.gif","alt":"[白条]"},{"url":"260@2x.gif","alt":"[白条]"},{"url":"261@2x.gif","alt":"[搬砖中]"},
{"url":"262@2x.gif","alt":"[脑壳疼]"},{"url":"263@2x.gif","alt":"[沧桑]"},{"url":"264@2x.gif","alt":"[捂脸]"},{"url":"265@2x.gif","alt":"[辣眼睛]"},{"url":"266@2x.gif","alt":"[哦呦]"},{"url":"267@2x.gif","alt":"[头秃]"},{"url":"268@2x.gif","alt":"[问号脸]"},
{"url":"269@2x.gif","alt":"[暗中观察]"},{"url":"270@2x.gif","alt":"[emm]"},{"url":"271@2x.gif","alt":"[吃瓜]"},{"url":"272@2x.gif","alt":"[呵呵哒]"},{"url":"273@2x.gif","alt":"[白条]"},{"url":"274@2x.gif","alt":"[白条]"},{"url":"newemoji_002.gif","alt":"[好的]"},
{"url":"newemoji_003.gif","alt":"[白眼]"},{"url":"newemoji_004.gif","alt":"[鬼脸]"},{"url":"newemoji_005.gif","alt":"[马赛克]"},{"url":"newemoji_006.gif","alt":"[喝茶]"},{"url":"newemoji_007.gif","alt":"[摸鱼]"},{"url":"newemoji_008.gif","alt":"[大笑]"},{"url":"newemoji_009.gif","alt":"[请滚]"},
{"url":"newemoji_010.gif","alt":"[睁眼]"},{"url":"newemoji_011.gif","alt":"[儿子乖]"},{"url":"newemoji_012.gif","alt":"[脸疼]"},{"url":"newemoji_013.gif","alt":"[考虑]"},{"url":"newemoji_014.gif","alt":"[惊掉下巴]"},{"url":"newemoji_015.gif","alt":"[遮眼]"},{"url":"newemoji_016.gif","alt":"[比爱心]"},
{"url":"newemoji_017.gif","alt":"[喝彩]"}
]
export default emojiList;
// const emojiList = [
// {"url":"0@2x.png","alt":"[惊讶]"},{"url":"1@2x.png","alt":"[撇嘴]"},{"url":"2@2x.png","alt":"[色]"},{"url":"3@2x.png","alt":"[啊这]"},{"url":"4@2x.png","alt":"[得意]"},{"url":"5@2x.png","alt":"[流泪]"},{"url":"6@2x.png","alt":"[害羞]"},
// {"url":"7@2x.png","alt":"[闭嘴]"},{"url":"8@2x.png","alt":"[睡]"},{"url":"9@2x.png","alt":"[大哭]"},{"url":"10@2x.png","alt":"[尴尬]"},{"url":"11@2x.png","alt":"[发怒]"},{"url":"12@2x.png","alt":"[调皮]"},{"url":"13@2x.png","alt":"[呲牙]"},
// {"url":"14@2x.png","alt":"[微笑]"},{"url":"15@2x.png","alt":"[难过]"},{"url":"16@2x.png","alt":"[酷]"},{"url":"18@2x.png","alt":"[抓狂]"},{"url":"19@2x.png","alt":"[吐]"},{"url":"20@2x.png","alt":"[偷笑]"},{"url":"21@2x.png","alt":"[可爱]"},
// {"url":"22@2x.png","alt":"[白眼]"},{"url":"23@2x.png","alt":"[傲慢]"},{"url":"24@2x.png","alt":"[饥饿]"},{"url":"25@2x.png","alt":"[困]"},{"url":"26@2x.png","alt":"[惊恐]"},{"url":"27@2x.png","alt":"[流汗]"},{"url":"28@2x.png","alt":"[憨笑]"},
// {"url":"29@2x.png","alt":"[悠闲]"},{"url":"30@2x.png","alt":"[奋斗]"},{"url":"31@2x.png","alt":"[咒骂]"},{"url":"32@2x.png","alt":"[疑问]"},{"url":"33@2x.png","alt":"[嘘]"},{"url":"34@2x.png","alt":"[晕]"},{"url":"35@2x.png","alt":"[折磨]"},
// {"url":"36@2x.png","alt":"[衰]"},{"url":"37@2x.png","alt":"[骷髅]"},{"url":"38@2x.png","alt":"[敲打]"},{"url":"39@2x.png","alt":"[再见]"},{"url":"46@2x.png","alt":"[猪头]"},{"url":"49@2x.png","alt":"[抱抱]"},{"url":"53@2x.png","alt":"[生日]"},
// {"url":"54@2x.png","alt":"[闪电]"},{"url":"55@2x.png","alt":"[炸弹]"},{"url":"56@2x.png","alt":"[刀]"},{"url":"57@2x.png","alt":"[足球]"},{"url":"59@2x.png","alt":"[便便]"},{"url":"60@2x.png","alt":"[咖啡]"},{"url":"61@2x.png","alt":"[饭]"},
// {"url":"62@2x.png","alt":"[药]"},{"url":"63@2x.png","alt":"[玫瑰]"},{"url":"64@2x.png","alt":"[凋谢]"},{"url":"66@2x.png","alt":"[爱心]"},{"url":"67@2x.png","alt":"[心碎]"},{"url":"69@2x.png","alt":"[礼物]"},{"url":"72@2x.png","alt":"[信封]"},
// {"url":"74@2x.png","alt":"[太阳]"},{"url":"75@2x.png","alt":"[月亮]"},{"url":"76@2x.png","alt":"[赞]"},{"url":"77@2x.png","alt":"[踩]"},{"url":"78@2x.png","alt":"[握手]"},{"url":"79@2x.png","alt":"[胜利]"},{"url":"89@2x.png","alt":"[西瓜]"},
// {"url":"90@2x.png","alt":"[下雨]"},{"url":"91@2x.png","alt":"[多云]"},{"url":"96@2x.png","alt":"[冷汗]"},{"url":"97@2x.png","alt":"[擦汗]"},{"url":"98@2x.png","alt":"[抠鼻]"},{"url":"99@2x.png","alt":"[鼓掌]"},{"url":"100@2x.png","alt":"[嗅大了]"},
// {"url":"101@2x.png","alt":"[坏笑]"},{"url":"102@2x.png","alt":"[右哼哼]"},{"url":"103@2x.png","alt":"[左哼哼]"},{"url":"104@2x.png","alt":"[哈欠]"},{"url":"105@2x.png","alt":"[鄙视]"},{"url":"106@2x.png","alt":"[委屈]"},{"url":"107@2x.png","alt":"[快哭了]"},
// {"url":"108@2x.png","alt":"[阴险]"},{"url":"109@2x.png","alt":"[亲亲]"},{"url":"110@2x.png","alt":"[吓]"},{"url":"111@2x.png","alt":"[可怜]"},{"url":"112@2x.png","alt":"[菜刀]"},{"url":"113@2x.png","alt":"[啤酒]"},{"url":"114@2x.png","alt":"[篮球]"},
// {"url":"115@2x.png","alt":"[乒乓]"},{"url":"116@2x.png","alt":"[示爱]"},{"url":"117@2x.png","alt":"[瓢虫]"},{"url":"118@2x.png","alt":"[抱拳]"},{"url":"119@2x.png","alt":"[勾引]"},{"url":"120@2x.png","alt":"[拳头]"},{"url":"121@2x.png","alt":"[差劲]"},
// {"url":"122@2x.png","alt":"[爱你]"},{"url":"123@2x.png","alt":"[NO]"},{"url":"124@2x.png","alt":"[OK]"},{"url":"136@2x.png","alt":"[双喜]"},{"url":"137@2x.png","alt":"[鞭炮]"},{"url":"138@2x.png","alt":"[灯笼]"},{"url":"139@2x.png","alt":"[麻将]"},
// {"url":"140@2x.png","alt":"[唱歌]"},{"url":"141@2x.png","alt":"[包包]"},{"url":"142@2x.png","alt":"[信]"},{"url":"143@2x.png","alt":"[象棋]"},{"url":"144@2x.png","alt":"[礼物]"},{"url":"145@2x.png","alt":"[祈祷]"},{"url":"146@2x.png","alt":"[爆筋]"},
// {"url":"147@2x.png","alt":"[棒棒糖]"},{"url":"148@2x.png","alt":"[喝奶]"},{"url":"149@2x.png","alt":"[吃面]"},{"url":"150@2x.png","alt":"[香蕉]"},{"url":"151@2x.png","alt":"[飞机]"},{"url":"152@2x.png","alt":"[汽车]"},{"url":"153@2x.png","alt":"[高铁]"},
// {"url":"154@2x.png","alt":"[动车]"},{"url":"155@2x.png","alt":"[动车头]"},{"url":"156@2x.png","alt":"[多云]"},{"url":"157@2x.png","alt":"[下雨]"},{"url":"158@2x.png","alt":"[钞票]"},{"url":"159@2x.png","alt":"[熊猫]"},{"url":"160@2x.png","alt":"[电灯泡]"},
// {"url":"161@2x.png","alt":"[七彩]"},{"url":"162@2x.png","alt":"[闹钟]"},{"url":"163@2x.png","alt":"[雨伞]"},{"url":"164@2x.png","alt":"[气球]"},{"url":"165@2x.png","alt":"[钻戒]"},{"url":"166@2x.png","alt":"[座椅]"},{"url":"167@2x.png","alt":"[纸巾]"},
// {"url":"168@2x.png","alt":"[药丸]"},{"url":"169@2x.png","alt":"[手枪]"},{"url":"170@2x.png","alt":"[青蛙]"},{"url":"171@2x.png","alt":"[热汤]"},{"url":"172@2x.png","alt":"[眨眼睛]"},{"url":"173@2x.png","alt":"[泪奔]"},{"url":"174@2x.png","alt":"[无奈]"},
// {"url":"175@2x.png","alt":"[卖萌]"},{"url":"176@2x.png","alt":"[小纠结]"},{"url":"177@2x.png","alt":"[喷血]"},{"url":"178@2x.png","alt":"[斜眼笑]"},{"url":"179@2x.png","alt":"[高傲]"},{"url":"180@2x.png","alt":"[惊喜]"},{"url":"181@2x.png","alt":"[骚扰]"},
// {"url":"182@2x.png","alt":"[笑哭]"},{"url":"183@2x.png","alt":"[我最美]"},{"url":"184@2x.png","alt":"[河蟹]"},{"url":"185@2x.png","alt":"[羊驼]"},{"url":"186@2x.png","alt":"[板栗]"},{"url":"187@2x.png","alt":"[幽灵]"},{"url":"188@2x.png","alt":"[鸡蛋]"},
// {"url":"189@2x.png","alt":"[魔方]"},{"url":"190@2x.png","alt":"[转花圈]"},{"url":"191@2x.png","alt":"[搓澡]"},{"url":"192@2x.png","alt":"[红包]"},{"url":"200@2x.png","alt":"[拜托]"},{"url":"201@2x.png","alt":"[点赞]"},{"url":"202@2x.png","alt":"[无聊]"},
// {"url":"203@2x.png","alt":"[托脸]"},{"url":"204@2x.png","alt":"[吃]"},{"url":"205@2x.png","alt":"[送花]"},{"url":"206@2x.png","alt":"[害怕]"},{"url":"207@2x.png","alt":"[花痴]"},{"url":"208@2x.png","alt":"[小样儿]"},{"url":"210@2x.png","alt":"[飙泪]"},
// {"url":"211@2x.png","alt":"[我不看]"},{"url":"212@2x.png","alt":"[托腮]"},{"url":"245@2x.png","alt":"[加油必胜]"},{"url":"246@2x.png","alt":"[抱抱]"},{"url":"247@2x.png","alt":"[白条]"},{"url":"260@2x.png","alt":"[白条]"},{"url":"261@2x.png","alt":"[搬砖中]"},
// {"url":"262@2x.png","alt":"[脑壳疼]"},{"url":"263@2x.png","alt":"[沧桑]"},{"url":"264@2x.png","alt":"[捂脸]"},{"url":"265@2x.png","alt":"[辣眼睛]"},{"url":"266@2x.png","alt":"[哦呦]"},{"url":"267@2x.png","alt":"[头秃]"},{"url":"268@2x.png","alt":"[问号脸]"},
// {"url":"269@2x.png","alt":"[暗中观察]"},{"url":"270@2x.png","alt":"[emm]"},{"url":"271@2x.png","alt":"[吃瓜]"},{"url":"272@2x.png","alt":"[呵呵哒]"},{"url":"273@2x.png","alt":"[白条]"},{"url":"274@2x.png","alt":"[白条]"},{"url":"newemoji_002.png","alt":"[好的]"},
// {"url":"newemoji_003.png","alt":"[白眼]"},{"url":"newemoji_004.png","alt":"[鬼脸]"},{"url":"newemoji_005.png","alt":"[马赛克]"},{"url":"newemoji_006.png","alt":"[喝茶]"},{"url":"newemoji_007.png","alt":"[摸鱼]"},{"url":"newemoji_008.png","alt":"[大笑]"},{"url":"newemoji_009.png","alt":"[请滚]"},
// {"url":"newemoji_010.png","alt":"[睁眼]"},{"url":"newemoji_011.png","alt":"[儿子乖]"},{"url":"newemoji_012.png","alt":"[脸疼]"},{"url":"newemoji_013.png","alt":"[考虑]"},{"url":"newemoji_014.png","alt":"[惊掉下巴]"},{"url":"newemoji_015.png","alt":"[遮眼]"},{"url":"newemoji_016.png","alt":"[比爱心]"},
// {"url":"newemoji_017.png","alt":"[喝彩]"}
// ]
// export default emojiList;

View File

@@ -0,0 +1,82 @@
<template>
<view
class="emotion-box"
style="display: flex; flex-direction: row; flex-wrap: wrap; height: 275px; overflow-y: scroll;"
>
<block v-for="(list, index) in emojilist" :key="index">
<view style="width: 10%; margin: 10px 3.3%;">
<image
@click="clickEmoji(list)"
:src="`/static/emojis/qq/${list.url}`"
style="width: 35px; height: 35px;"
/>
</view>
</block>
</view>
</template>
<script setup>
import { ref, onMounted, defineProps, defineEmits } from 'vue'
import emojiList1 from './emoji/biaoqing.js'
const props = defineProps({
windowWidth: {
type: Number,
default: 320,
},
})
const emit = defineEmits(['emotion'])
const emojilist = ref(emojiList1)
const img_width = ref(0)
onMounted(() => {
const query = uni.createSelectorQuery().in(this)
query
.select('.emotion-box')
.boundingClientRect((data) => {
img_width.value = props.windowWidth / 10
})
.exec()
})
/**
* 点击表情事件
*/
function clickEmoji(val) {
const emotioni = val.alt
const emotion = getEmotion(val.url)
console.log(emotion)
emit('emotion', { emotion, emotioni })
}
/**
* 根据表情 url 生成完整图片路径
*/
function getEmotion(res) {
return `https://www.amazinglimited.com/emoji/qq/${res}`
}
</script>
<style scoped>
.emotion-box {
margin: 0 auto;
width: 100%;
box-sizing: border-box;
padding-top: 8upx;
overflow: hidden;
background: white;
}
.emotion-box-line {
display: flex;
}
.emotion-item {
flex: 1;
text-align: center;
cursor: pointer;
padding: 10upx;
}
</style>

View File

@@ -24,7 +24,8 @@
<view class="actions">
<view class="action-btn" @click="handleLike(comment)">
<wd-icon
:name="comment.isLike ? 'heart-filled' : 'heart'"
:name="comment.isLike ? 'heart-filled' : 'heart'"
:color="comment.isLike ? 'red' : 'gray'"
size="18px"
/>
<text>{{ comment.likeCount || 0 }}</text>

View File

@@ -2,8 +2,8 @@
<view class="navbar">
<view class="statusBar" :style="{height:getStatusBarHeight()+'px'}"></view>
<view class="titleBar" :style="{height:getTitleBarHeight()+'px'}">
<wd-navbar v-if="title" :title="title" :left-arrow="leftArrow" @click="handleClickLeft"></wd-navbar>
<wd-navbar v-else :left-arrow="leftArrow" @click="handleClickLeft">
<wd-navbar v-if="title" :title="title" :left-arrow="leftArrow" @click-left="handleClickLeft"></wd-navbar>
<wd-navbar v-else :left-arrow="leftArrow" @click-left="handleClickLeft">
<template #title>
<slot name="title"></slot>
</template>
@@ -14,8 +14,7 @@
</template>
<script setup>
import { ref } from 'vue';
import { getStatusBarHeight, getTitleBarHeight, getNavBarHeight, getLeftIconLeft} from "@/utils/system"
import { getStatusBarHeight, getTitleBarHeight, getNavBarHeight } from "@/utils/system"
defineProps({
title:{

View File

@@ -224,7 +224,8 @@
"type_2": "Page Turn",
"voices_null": "No audio available",
"endText": "Trial ended, purchase to continue",
"language": "Book language"
"language": "Book language",
"readAudio": "Loading audio..."
},
"bookDetails": {
"title": "Book Details",

View File

@@ -225,7 +225,8 @@
"type_2": "左右翻页",
"voices_null": "暂无音频文件",
"endText": "试读已结束,购买后继续阅读",
"language": "书籍语言"
"language": "书籍语言",
"readAudio": "音频加载中..."
},
"bookDetails": {
"title": "书籍详情",

View File

@@ -180,7 +180,7 @@
import { ref, onMounted } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import { useI18n } from 'vue-i18n'
import { homeApi } from '@/api/modules/home'
import { homeApi } from '@/api/modules/book_home'
import type {
IBook,
IBookWithStats,
@@ -488,7 +488,6 @@ onShow(() => {
background-size: cover;
padding: 30rpx;
position: relative;
height: 340rpx;
.icon-hua {
width: 100%;

View File

@@ -4,21 +4,16 @@
<nav-bar :title="currentChapter.chapter"></nav-bar>
<view class="player-content" :style="{ height: contentHeight + 'px' }">
<!-- 封面 -->
<view class="cover-section">
<image
:src="bookInfo.images"
class="cover-image"
:class="{ rotating: isPlaying }"
mode="aspectFill"
/>
</view>
<!-- 章节信息 -->
<view class="chapter-info">
<text class="chapter-title">{{ currentChapter.chapter }}</text>
<text v-if="currentChapter.content" class="chapter-subtitle">{{ currentChapter.content }}</text>
</view>
<!-- 文字内容区域 -->
<scroll-view
class="content-section"
scroll-y
:scroll-into-view="scrollIntoViewId"
>
<view id="content-top">
<text class="content-text">{{ currentContent }}</text>
</view>
</scroll-view>
<!-- 进度条 -->
<view class="progress-section">
@@ -126,6 +121,12 @@ const currentChapter = ref<IChapter>({
voices: ''
})
// 内容相关
const currentContent = ref('') // 当前显示的文字内容
const contentDataList = ref<any[]>([]) // 章节内容数据列表
const voicesTimeList = ref<number[]>([]) // 音频时间点数组
const scrollIntoViewId = ref('') // 滚动控制
// 音频状态
const audioContext = ref<UniApp.InnerAudioContext | null>(null)
const isPlaying = ref(false)
@@ -200,6 +201,9 @@ function initAudioContext() {
isPlaying.value = false
})
let lastUpdateTime = -1
let lastContentIndex = -1
audioContext.value.onTimeUpdate(() => {
if (!isChanging.value && audioContext.value) {
currentTime.value = audioContext.value.currentTime
@@ -207,6 +211,21 @@ function initAudioContext() {
if (duration.value > 0) {
progress.value = (currentTime.value / duration.value) * 100
}
// 根据音频时间更新文字内容
const currentTimeFloor = Math.floor(currentTime.value)
if (currentTimeFloor !== lastUpdateTime) {
lastUpdateTime = currentTimeFloor
// 查找当前时间对应的内容索引
const contentIndex = voicesTimeList.value.indexOf(currentTimeFloor)
if (contentIndex !== -1 && contentIndex !== lastContentIndex) {
lastContentIndex = contentIndex
if (contentDataList.value[contentIndex]) {
currentContent.value = contentDataList.value[contentIndex].content || ''
}
}
}
}
})
@@ -239,25 +258,101 @@ async function loadBookInfo() {
// 加载章节列表
async function loadChapterList() {
try {
uni.showLoading({ title: t('common.loading') })
const res = await bookApi.getBookChapter({
bookId: bookId.value
})
console.log('章节列表响应:', res)
if (res.chapterList && res.chapterList.length > 0) {
chapterList.value = res.chapterList
// 播放当前章节
uni.hideLoading()
// 加载当前章节内容
if (currentChapterIndex.value < chapterList.value.length) {
playChapter(chapterList.value[currentChapterIndex.value])
const currentChapter = chapterList.value[currentChapterIndex.value]
console.log('当前章节:', currentChapter)
await loadChapterContent(currentChapter.id)
playChapter(currentChapter)
}
} else {
uni.hideLoading()
uni.showToast({
title: '章节列表为空',
icon: 'none'
})
}
} catch (error) {
uni.hideLoading()
console.error('Failed to load chapter list:', error)
uni.showToast({
title: '加载章节失败',
icon: 'none'
})
}
}
// 加载章节内容(带音频时间点)
async function loadChapterContent(chapterId: number) {
try {
uni.showLoading({ title: t('common.loading') })
console.log('加载章节内容, chapterId:', chapterId)
const res = await bookApi.getChapterContentListen(chapterId)
console.log('章节内容响应:', res)
if (res.bookChapterContents && res.bookChapterContents.length > 0) {
contentDataList.value = res.bookChapterContents
// 提取音频时间点数组
voicesTimeList.value = res.bookChapterContents.map((item: any) =>
Number(item.voicesStart || 0)
)
console.log('音频时间点数组:', voicesTimeList.value)
// 显示第一段内容
if (res.bookChapterContents[0]) {
currentContent.value = res.bookChapterContents[0].content || ''
console.log('第一段内容:', currentContent.value.substring(0, 50))
}
// 滚动到顶部
scrollToTop()
} else {
console.log('章节内容为空')
currentContent.value = '暂无内容'
}
uni.hideLoading()
} catch (error) {
console.error('Failed to load chapter content:', error)
uni.hideLoading()
uni.showToast({
title: '加载内容失败',
icon: 'none'
})
}
}
// 滚动到顶部
function scrollToTop() {
scrollIntoViewId.value = 'content-top'
setTimeout(() => {
scrollIntoViewId.value = ''
}, 300)
}
// 播放章节
function playChapter(chapter: IChapter) {
console.log('播放章节:', chapter)
if (!chapter.voices) {
console.log('章节没有音频文件')
uni.showToast({
title: t('book.voices_null'),
icon: 'none'
@@ -268,9 +363,21 @@ function playChapter(chapter: IChapter) {
currentChapter.value = chapter
if (audioContext.value) {
console.log('设置音频源:', chapter.voices)
uni.showLoading({ title: t('common.readAudio') })
audioContext.value.src = chapter.voices
audioContext.value.playbackRate = playbackRate.value
// 监听音频准备就绪
audioContext.value.onCanplay(() => {
console.log('音频准备就绪')
uni.hideLoading()
})
audioContext.value.play()
} else {
console.log('音频上下文未初始化')
}
}
@@ -286,20 +393,21 @@ function togglePlay() {
}
// 上一章
function prevChapter() {
async function prevChapter() {
if (currentChapterIndex.value > 0) {
currentChapterIndex.value--
await loadChapterContent(chapterList.value[currentChapterIndex.value].id)
playChapter(chapterList.value[currentChapterIndex.value])
} else {
uni.showToast({
title: '已经是第一章了',
title: t('listen.earlier'),
icon: 'none'
})
}
}
// 下一章
function nextChapter() {
async function nextChapter() {
// 检查是否锁定
if (isBuy.value === '1' && currentChapterIndex.value + 1 >= count.value) {
uni.showModal({
@@ -319,10 +427,11 @@ function nextChapter() {
if (currentChapterIndex.value < chapterList.value.length - 1) {
currentChapterIndex.value++
await loadChapterContent(chapterList.value[currentChapterIndex.value].id)
playChapter(chapterList.value[currentChapterIndex.value])
} else {
uni.showToast({
title: '已经是最后一章了',
title: t('listen.behind'),
icon: 'none'
})
}
@@ -360,6 +469,20 @@ function onProgressChange(e: any) {
if (audioContext.value && duration.value > 0) {
const newTime = (value / 100) * duration.value
audioContext.value.seek(newTime)
// 更新文字内容
const seekTimeFloor = Math.floor(newTime)
for (let i = voicesTimeList.value.length - 1; i >= 0; i--) {
if (seekTimeFloor >= voicesTimeList.value[i]) {
if (contentDataList.value[i]) {
currentContent.value = contentDataList.value[i].content || ''
}
break
}
}
// 滚动到顶部
scrollToTop()
}
setTimeout(() => {
isChanging.value = false
@@ -380,18 +503,30 @@ function changeChapter() {
}
// 选择章节
function selectChapter(index: number) {
async function selectChapter(index: number) {
if (index === currentChapterIndex.value) {
showChapterSelect.value = false
return
}
// 检查是否锁定
if (isBuy.value === '1' && index >= count.value) {
uni.showToast({
title: t('book.afterPurchase'),
icon: 'none'
})
return
}
// 更新当前章节索引
currentChapterIndex.value = index
// 关闭弹窗
showChapterSelect.value = false
// 加载章节内容
await loadChapterContent(chapterList.value[index].id)
// 播放选中的章节
playChapter(chapterList.value[index])
}
@@ -408,7 +543,7 @@ function formatTime(seconds: number): string {
<style lang="scss" scoped>
.audio-player-page {
background: linear-gradient(180deg, #f7faf9 0%, #fff 100%);
background: linear-gradient(180deg, #fdfcfb 30%, #eef0cf 100%);
min-height: 100vh;
.player-content {
@@ -416,43 +551,20 @@ function formatTime(seconds: number): string {
flex-direction: column;
padding: 40rpx 40rpx;
.cover-section {
.content-section {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
height: 600rpx;
margin-bottom: 60rpx;
padding: 30rpx;
border-radius: 20rpx;
.cover-image {
width: 400rpx;
height: 400rpx;
border-radius: 50%;
box-shadow: 0 10rpx 40rpx rgba(0, 0, 0, 0.1);
&.rotating {
animation: rotate 20s linear infinite;
}
}
}
.chapter-info {
text-align: center;
margin-bottom: 60rpx;
.chapter-title {
.content-text {
display: block;
font-size: 40rpx;
font-weight: bold;
font-size: 36rpx;
line-height: 60rpx;
color: #333;
line-height: 50rpx;
margin-bottom: 20rpx;
}
.chapter-subtitle {
display: block;
font-size: 28rpx;
color: #666;
line-height: 36rpx;
letter-spacing: 0.1rem;
text-align: justify;
}
}

View File

@@ -52,7 +52,7 @@
<wd-popup v-model="commentVisible" position="bottom">
<view class="comment-dialog">
<text class="dialog-title">
{{ replyTarget ? $t('bookDetails.reply') + replyTarget.name + $t('bookDetails.dpl') : $t('bookDetails.makeComment') }}
{{ replyTarget ? $t('bookDetails.reply') + '"' + replyTarget.name + '"' + $t('bookDetails.dpl') : $t('bookDetails.makeComment') }}
</text>
<!-- 富文本编辑器 -->
@@ -73,7 +73,7 @@
<!-- 这里需要一个Emoji选择器组件暂时简化处理 -->
<view v-if="showEmoji" class="emoji-picker">
<text class="emoji-tip">Emoji功能待集成</text>
<EmotionPicker @emotion="handleEmj" :height="220"></EmotionPicker>
</view>
</view>
@@ -95,8 +95,8 @@ import { onLoad } from '@dcloudio/uni-app'
import { useI18n } from 'vue-i18n'
import { bookApi } from '@/api/modules/book'
import type { IBookDetail, IComment } from '@/types/book'
import CustomNavbar from '@/components/book/CustomNavbar.vue'
import CommentList from '@/components/book/CommentList.vue'
import EmotionPicker from '@/components/bkhumor-emojiplus/index.vue'
const { t } = useI18n()
@@ -220,7 +220,7 @@ function showCommentDialog(comment?: IComment) {
if (comment) {
const userName = comment.userEntity.nickname || comment.userEntity.name || 'TA'
replyTarget.value = { id: comment.id, name: userName }
placeholder.value = t('bookDetails.replyText') + userName + t('bookDetails.dpl')
placeholder.value = t('bookDetails.replyText') + '"' + userName + '"' + t('bookDetails.dpl')
} else {
replyTarget.value = null
placeholder.value = t('bookDetails.enterText')
@@ -266,6 +266,16 @@ function getEditorContent(): Promise<string> {
})
}
//获得输入的表情数组
function handleEmj(i: any) {
editorCtx.value.insertImage({
src: i.emotion,
alt: "emoji",
className: 'emoji_image',
success: function() {},
});
}
// 提交评论
async function submitComment() {
try {
@@ -465,9 +475,17 @@ function toggleEmoji() {
border: 1rpx solid #ddd;
width: 100%;
min-height: 200rpx;
height: 200rpx;
padding: 10rpx;
border-radius: 10rpx;
margin-bottom: 20rpx;
:deep() .ql-editor {
img {
width: 44rpx;
height: 44rpx;
}
}
}
.emoji-section {
@@ -482,8 +500,8 @@ function toggleEmoji() {
padding-top: 20rpx;
image {
width: 45rpx;
height: 45rpx;
width: 44rpx;
height: 44rpx;
display: block;
margin: 0 auto 5rpx;
}
@@ -498,10 +516,7 @@ function toggleEmoji() {
.emoji-picker {
margin-top: 20rpx;
padding: 20rpx;
background: #f4f5f7;
border-radius: 10rpx;
.emoji-tip {
font-size: 26rpx;
color: #999;

View File

@@ -46,7 +46,7 @@
import { ref, onMounted } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { useI18n } from 'vue-i18n'
import { homeApi } from '@/api/modules/home'
import { homeApi } from '@/api/modules/book_home'
import type { IBookWithStats, IVipInfo } from '@/types/home'
const { t } = useI18n()
@@ -93,7 +93,7 @@ const handleSearch = async () => {
try {
const res = await homeApi.searchBooks({
key: keyword.value.trim(),
title: keyword.value.trim(),
page: 1,
limit: 10,
})
@@ -196,6 +196,7 @@ onMounted(async () => {
:deep() {
.wd-search {
background: transparent;
width: 100%;
}
}
}

View File

@@ -431,7 +431,6 @@ $border-color: #eeeeee;
background-size: cover;
padding: 30rpx;
position: relative;
height: 340rpx;
.icon-hua {
width: 100%;

BIN
static/course/nobg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 72 KiB

View File

@@ -1,530 +0,0 @@
/*! tailwindcss v4.1.16 | MIT License | https://tailwindcss.com */
@layer properties;
@layer theme, base, components, utilities;
@layer theme {
:root, :host {
--font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji",
"Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
"Courier New", monospace;
--color-red-500: oklch(63.7% 0.237 25.331);
--ease-out: cubic-bezier(0, 0, 0.2, 1);
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
--default-transition-duration: 150ms;
--default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
--default-font-family: var(--font-sans);
--default-mono-font-family: var(--font-mono);
}
}
@layer base {
*, ::after, ::before, ::backdrop, ::file-selector-button {
box-sizing: border-box;
margin: 0;
padding: 0;
border: 0 solid;
}
html, :host {
line-height: 1.5;
-webkit-text-size-adjust: 100%;
tab-size: 4;
font-family: var(--default-font-family, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");
font-feature-settings: var(--default-font-feature-settings, normal);
font-variation-settings: var(--default-font-variation-settings, normal);
-webkit-tap-highlight-color: transparent;
}
hr {
height: 0;
color: inherit;
border-top-width: 1px;
}
abbr:where([title]) {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
}
h1, h2, h3, h4, h5, h6 {
font-size: inherit;
font-weight: inherit;
}
a {
color: inherit;
-webkit-text-decoration: inherit;
text-decoration: inherit;
}
b, strong {
font-weight: bolder;
}
code, kbd, samp, pre {
font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);
font-feature-settings: var(--default-mono-font-feature-settings, normal);
font-variation-settings: var(--default-mono-font-variation-settings, normal);
font-size: 1em;
}
small {
font-size: 80%;
}
sub, sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
table {
text-indent: 0;
border-color: inherit;
border-collapse: collapse;
}
:-moz-focusring {
outline: auto;
}
progress {
vertical-align: baseline;
}
summary {
display: list-item;
}
ol, ul, menu {
list-style: none;
}
img, svg, video, canvas, audio, iframe, embed, object {
display: block;
vertical-align: middle;
}
img, video {
max-width: 100%;
height: auto;
}
button, input, select, optgroup, textarea, ::file-selector-button {
font: inherit;
font-feature-settings: inherit;
font-variation-settings: inherit;
letter-spacing: inherit;
color: inherit;
border-radius: 0;
background-color: transparent;
opacity: 1;
}
:where(select:is([multiple], [size])) optgroup {
font-weight: bolder;
}
:where(select:is([multiple], [size])) optgroup option {
padding-inline-start: 20px;
}
::file-selector-button {
margin-inline-end: 4px;
}
::placeholder {
opacity: 1;
}
@supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) {
::placeholder {
color: currentcolor;
@supports (color: color-mix(in lab, red, red)) {
color: color-mix(in oklab, currentcolor 50%, transparent);
}
}
}
textarea {
resize: vertical;
}
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-date-and-time-value {
min-height: 1lh;
text-align: inherit;
}
::-webkit-datetime-edit {
display: inline-flex;
}
::-webkit-datetime-edit-fields-wrapper {
padding: 0;
}
::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field {
padding-block: 0;
}
::-webkit-calendar-picker-indicator {
line-height: 1;
}
:-moz-ui-invalid {
box-shadow: none;
}
button, input:where([type="button"], [type="reset"], [type="submit"]), ::file-selector-button {
appearance: button;
}
::-webkit-inner-spin-button, ::-webkit-outer-spin-button {
height: auto;
}
[hidden]:where(:not([hidden="until-found"])) {
display: none !important;
}
}
@layer utilities {
.collapse {
visibility: collapse;
}
.visible {
visibility: visible;
}
.absolute {
position: absolute;
}
.fixed {
position: fixed;
}
.relative {
position: relative;
}
.static {
position: static;
}
.sticky {
position: sticky;
}
.container {
width: 100%;
@media (width >= 40rem) {
max-width: 40rem;
}
@media (width >= 48rem) {
max-width: 48rem;
}
@media (width >= 64rem) {
max-width: 64rem;
}
@media (width >= 80rem) {
max-width: 80rem;
}
@media (width >= 96rem) {
max-width: 96rem;
}
}
.block {
display: block;
}
.contents {
display: contents;
}
.flex {
display: flex;
}
.grid {
display: grid;
}
.hidden {
display: none;
}
.inline {
display: inline;
}
.inline-block {
display: inline-block;
}
.table {
display: table;
}
.w-\[100px\] {
width: 100px;
}
.flex-1 {
flex: 1;
}
.flex-shrink {
flex-shrink: 1;
}
.transform {
transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);
}
.resize {
resize: both;
}
.flex-wrap {
flex-wrap: wrap;
}
.border {
border-style: var(--tw-border-style);
border-width: 1px;
}
.bg-\[blue\] {
background-color: blue;
}
.bg-\[red\] {
background-color: red;
}
.bg-\[transparent\] {
background-color: transparent;
}
.text-center {
text-align: center;
}
.text-\[\#000\] {
color: #000;
}
.text-\[\#fff\] {
color: #fff;
}
.lowercase {
text-transform: lowercase;
}
.uppercase {
text-transform: uppercase;
}
.ordinal {
--tw-ordinal: ordinal;
font-variant-numeric: var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,);
}
.ring {
--tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
}
.outline {
outline-style: var(--tw-outline-style);
outline-width: 1px;
}
.blur {
--tw-blur: blur(8px);
filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
}
.filter {
filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
}
.transition {
transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, content-visibility, overlay, pointer-events;
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
transition-duration: var(--tw-duration, var(--default-transition-duration));
}
.ease-in-out {
--tw-ease: var(--ease-in-out);
transition-timing-function: var(--ease-in-out);
}
.hover\:bg-red-500 {
&:hover {
@media (hover: hover) {
background-color: var(--color-red-500);
}
}
}
}
@property --tw-rotate-x {
syntax: "*";
inherits: false;
}
@property --tw-rotate-y {
syntax: "*";
inherits: false;
}
@property --tw-rotate-z {
syntax: "*";
inherits: false;
}
@property --tw-skew-x {
syntax: "*";
inherits: false;
}
@property --tw-skew-y {
syntax: "*";
inherits: false;
}
@property --tw-border-style {
syntax: "*";
inherits: false;
initial-value: solid;
}
@property --tw-ordinal {
syntax: "*";
inherits: false;
}
@property --tw-slashed-zero {
syntax: "*";
inherits: false;
}
@property --tw-numeric-figure {
syntax: "*";
inherits: false;
}
@property --tw-numeric-spacing {
syntax: "*";
inherits: false;
}
@property --tw-numeric-fraction {
syntax: "*";
inherits: false;
}
@property --tw-shadow {
syntax: "*";
inherits: false;
initial-value: 0 0 #0000;
}
@property --tw-shadow-color {
syntax: "*";
inherits: false;
}
@property --tw-shadow-alpha {
syntax: "<percentage>";
inherits: false;
initial-value: 100%;
}
@property --tw-inset-shadow {
syntax: "*";
inherits: false;
initial-value: 0 0 #0000;
}
@property --tw-inset-shadow-color {
syntax: "*";
inherits: false;
}
@property --tw-inset-shadow-alpha {
syntax: "<percentage>";
inherits: false;
initial-value: 100%;
}
@property --tw-ring-color {
syntax: "*";
inherits: false;
}
@property --tw-ring-shadow {
syntax: "*";
inherits: false;
initial-value: 0 0 #0000;
}
@property --tw-inset-ring-color {
syntax: "*";
inherits: false;
}
@property --tw-inset-ring-shadow {
syntax: "*";
inherits: false;
initial-value: 0 0 #0000;
}
@property --tw-ring-inset {
syntax: "*";
inherits: false;
}
@property --tw-ring-offset-width {
syntax: "<length>";
inherits: false;
initial-value: 0px;
}
@property --tw-ring-offset-color {
syntax: "*";
inherits: false;
initial-value: #fff;
}
@property --tw-ring-offset-shadow {
syntax: "*";
inherits: false;
initial-value: 0 0 #0000;
}
@property --tw-outline-style {
syntax: "*";
inherits: false;
initial-value: solid;
}
@property --tw-blur {
syntax: "*";
inherits: false;
}
@property --tw-brightness {
syntax: "*";
inherits: false;
}
@property --tw-contrast {
syntax: "*";
inherits: false;
}
@property --tw-grayscale {
syntax: "*";
inherits: false;
}
@property --tw-hue-rotate {
syntax: "*";
inherits: false;
}
@property --tw-invert {
syntax: "*";
inherits: false;
}
@property --tw-opacity {
syntax: "*";
inherits: false;
}
@property --tw-saturate {
syntax: "*";
inherits: false;
}
@property --tw-sepia {
syntax: "*";
inherits: false;
}
@property --tw-drop-shadow {
syntax: "*";
inherits: false;
}
@property --tw-drop-shadow-color {
syntax: "*";
inherits: false;
}
@property --tw-drop-shadow-alpha {
syntax: "<percentage>";
inherits: false;
initial-value: 100%;
}
@property --tw-drop-shadow-size {
syntax: "*";
inherits: false;
}
@property --tw-ease {
syntax: "*";
inherits: false;
}
@layer properties {
@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
*, ::before, ::after, ::backdrop {
--tw-rotate-x: initial;
--tw-rotate-y: initial;
--tw-rotate-z: initial;
--tw-skew-x: initial;
--tw-skew-y: initial;
--tw-border-style: solid;
--tw-ordinal: initial;
--tw-slashed-zero: initial;
--tw-numeric-figure: initial;
--tw-numeric-spacing: initial;
--tw-numeric-fraction: initial;
--tw-shadow: 0 0 #0000;
--tw-shadow-color: initial;
--tw-shadow-alpha: 100%;
--tw-inset-shadow: 0 0 #0000;
--tw-inset-shadow-color: initial;
--tw-inset-shadow-alpha: 100%;
--tw-ring-color: initial;
--tw-ring-shadow: 0 0 #0000;
--tw-inset-ring-color: initial;
--tw-inset-ring-shadow: 0 0 #0000;
--tw-ring-inset: initial;
--tw-ring-offset-width: 0px;
--tw-ring-offset-color: #fff;
--tw-ring-offset-shadow: 0 0 #0000;
--tw-outline-style: solid;
--tw-blur: initial;
--tw-brightness: initial;
--tw-contrast: initial;
--tw-grayscale: initial;
--tw-hue-rotate: initial;
--tw-invert: initial;
--tw-opacity: initial;
--tw-saturate: initial;
--tw-sepia: initial;
--tw-drop-shadow: initial;
--tw-drop-shadow-color: initial;
--tw-drop-shadow-alpha: 100%;
--tw-drop-shadow-size: initial;
--tw-ease: initial;
}
}
}

View File

@@ -8,12 +8,6 @@
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
"Courier New", monospace;
--color-red-500: oklch(63.7% 0.237 25.331);
--color-blue-500: oklch(62.3% 0.214 259.815);
--color-white: #fff;
--spacing: 0.25rem;
--font-weight-bold: 700;
--radius-lg: 0.5rem;
--ease-out: cubic-bezier(0, 0, 0.2, 1);
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
--default-transition-duration: 150ms;
--default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
@@ -209,69 +203,6 @@
max-width: 96rem;
}
}
.m-2 {
margin: calc(var(--spacing) * 2);
}
.mx-2 {
margin-inline: calc(var(--spacing) * 2);
}
.mx-4 {
margin-inline: calc(var(--spacing) * 4);
}
.mx-auto {
margin-inline: auto;
}
.my-3 {
margin-block: calc(var(--spacing) * 3);
}
.mt-1 {
margin-top: calc(var(--spacing) * 1);
}
.mt-2 {
margin-top: calc(var(--spacing) * 2);
}
.mt-4 {
margin-top: calc(var(--spacing) * 4);
}
.mr-2 {
margin-right: calc(var(--spacing) * 2);
}
.mr-3 {
margin-right: calc(var(--spacing) * 3);
}
.mr-4 {
margin-right: calc(var(--spacing) * 4);
}
.mb-2 {
margin-bottom: calc(var(--spacing) * 2);
}
.mb-3 {
margin-bottom: calc(var(--spacing) * 3);
}
.mb-4 {
margin-bottom: calc(var(--spacing) * 4);
}
.mb-5 {
margin-bottom: calc(var(--spacing) * 5);
}
.ml-2 {
margin-left: calc(var(--spacing) * 2);
}
.ml-3 {
margin-left: calc(var(--spacing) * 3);
}
.line-clamp-1 {
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}
.line-clamp-2 {
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.block {
display: block;
}
@@ -296,74 +227,28 @@
.table {
display: table;
}
.h-full {
height: 100%;
}
.min-h-screen {
min-height: 100vh;
}
.w-\[100px\] {
width: 100px;
}
.w-full {
width: 100%;
}
.flex-1 {
flex: 1;
}
.flex-shrink {
flex-shrink: 1;
}
.flex-shrink-0 {
flex-shrink: 0;
}
.border-collapse {
border-collapse: collapse;
}
.transform {
transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);
}
.resize {
resize: both;
}
.flex-col {
flex-direction: column;
}
.flex-wrap {
flex-wrap: wrap;
}
.items-center {
align-items: center;
}
.justify-around {
justify-content: space-around;
}
.justify-between {
justify-content: space-between;
}
.justify-center {
justify-content: center;
}
.overflow-hidden {
overflow: hidden;
}
.rounded {
border-radius: 0.25rem;
}
.rounded-full {
border-radius: calc(infinity * 1px);
}
.rounded-lg {
border-radius: var(--radius-lg);
}
.border {
border-style: var(--tw-border-style);
border-width: 1px;
}
.border-t {
border-top-style: var(--tw-border-style);
border-top-width: 1px;
}
.bg-\[blue\] {
background-color: blue;
}
@@ -373,92 +258,15 @@
.bg-\[transparent\] {
background-color: transparent;
}
.bg-blue-500 {
background-color: var(--color-blue-500);
}
.bg-white {
background-color: var(--color-white);
}
.bg-gradient-to-br {
--tw-gradient-position: to bottom right in oklab;
background-image: linear-gradient(var(--tw-gradient-stops));
}
.p-2 {
padding: calc(var(--spacing) * 2);
}
.p-3 {
padding: calc(var(--spacing) * 3);
}
.p-4 {
padding: calc(var(--spacing) * 4);
}
.p-5 {
padding: calc(var(--spacing) * 5);
}
.p-\[5px\] {
padding: 5px;
}
.px-2 {
padding-inline: calc(var(--spacing) * 2);
}
.px-3 {
padding-inline: calc(var(--spacing) * 3);
}
.px-4 {
padding-inline: calc(var(--spacing) * 4);
}
.px-5 {
padding-inline: calc(var(--spacing) * 5);
}
.px-20 {
padding-inline: calc(var(--spacing) * 20);
}
.py-1 {
padding-block: calc(var(--spacing) * 1);
}
.py-2 {
padding-block: calc(var(--spacing) * 2);
}
.py-3 {
padding-block: calc(var(--spacing) * 3);
}
.py-5 {
padding-block: calc(var(--spacing) * 5);
}
.py-10 {
padding-block: calc(var(--spacing) * 10);
}
.py-20 {
padding-block: calc(var(--spacing) * 20);
}
.pt-1 {
padding-top: calc(var(--spacing) * 1);
}
.pt-2 {
padding-top: calc(var(--spacing) * 2);
}
.pb-5 {
padding-bottom: calc(var(--spacing) * 5);
}
.pb-10 {
padding-bottom: calc(var(--spacing) * 10);
}
.text-center {
text-align: center;
}
.font-bold {
--tw-font-weight: var(--font-weight-bold);
font-weight: var(--font-weight-bold);
}
.text-\[\#000\] {
color: #000;
}
.text-\[\#fff\] {
color: #fff;
}
.text-white {
color: var(--color-white);
}
.lowercase {
text-transform: lowercase;
}
@@ -469,20 +277,6 @@
--tw-ordinal: ordinal;
font-variant-numeric: var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,);
}
.line-through {
text-decoration-line: line-through;
}
.underline {
text-decoration-line: underline;
}
.shadow {
--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
}
.shadow-sm {
--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
}
.ring {
--tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
@@ -515,6 +309,17 @@
}
}
}
@layer base {
html, :host {
line-height: 1.2;
}
img, svg, video, canvas, audio, iframe, embed, object {
display: inline-block;
}
button {
line-height: inherit;
}
}
@property --tw-rotate-x {
syntax: "*";
inherits: false;
@@ -540,10 +345,6 @@
inherits: false;
initial-value: solid;
}
@property --tw-font-weight {
syntax: "*";
inherits: false;
}
@property --tw-ordinal {
syntax: "*";
inherits: false;
@@ -700,7 +501,6 @@
--tw-skew-x: initial;
--tw-skew-y: initial;
--tw-border-style: solid;
--tw-font-weight: initial;
--tw-ordinal: initial;
--tw-slashed-zero: initial;
--tw-numeric-figure: initial;

View File

@@ -1 +1,13 @@
@import "tailwindcss";
@import "tailwindcss";
@layer base {
html, :host {
line-height: 1.2; /* 改掉默认的1.5 */
}
/* 覆盖 Tailwind 的默认 block 样式 */
img, svg, video, canvas, audio, iframe, embed, object {
display: inline-block;
}
button {
line-height: inherit;
}
}