调整资源对应的组件
This commit is contained in:
parent
275aacce23
commit
0b487b6d68
@ -115,4 +115,16 @@ export const xsJzListByXsIdApi = async (params: any) => {
|
||||
return await get("/api/jz/getListByXsId", params);
|
||||
};
|
||||
|
||||
// 教学资源树形
|
||||
export const typesFindTreeApi = async () => {
|
||||
return await get("/api/types/qryTreeReturn");
|
||||
};
|
||||
|
||||
// 获取资源分页
|
||||
export const resourcesFindPageApi = async (params: any) => {
|
||||
return await get("/api/resources/findPage", params);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
</template>
|
||||
<template #empty>
|
||||
<view class="flex-col-center">
|
||||
<view v-if="showNoDataImage" style="width: 300rpx;height: 300rpx">
|
||||
<view style="width: 300rpx;height: 300rpx">
|
||||
<image src="@/static/system/currency/zwjl.png" class="wh-full"/>
|
||||
</view>
|
||||
<view class="color-9">暂无数据...</view>
|
||||
@ -19,7 +19,7 @@
|
||||
</view>
|
||||
</template>
|
||||
<view class="p-15">
|
||||
<view v-for="(item,index) in dataList" :key="item.id||index">
|
||||
<view v-for="(item,index) in dataList" :key="item.id || index">
|
||||
<slot :data="item" :index="index" :list="dataList"/>
|
||||
</view>
|
||||
</view>
|
||||
@ -29,10 +29,10 @@
|
||||
</z-paging>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import {reactive, watch, computed} from "vue";
|
||||
import {reactive} from "vue";
|
||||
import type {LayoutOptions, PagingRefInterface} from "@/components/BasicListLayout/type/useLayout";
|
||||
|
||||
const dataList = ref([])
|
||||
const dataList = ref<any>([])
|
||||
const fixed = ref(false)
|
||||
const pagingRef = ref<PagingRefInterface | null>(null)
|
||||
|
||||
@ -41,6 +41,7 @@ const config = {
|
||||
'loading-full-fixed': true,
|
||||
}
|
||||
|
||||
|
||||
let componentProps = ref<any>({})
|
||||
const emits = defineEmits(['register'])
|
||||
let props: LayoutOptions
|
||||
@ -48,7 +49,7 @@ const setProps = (propValue: LayoutOptions) => {
|
||||
componentProps.value = propValue.componentProps ? propValue.componentProps : {}
|
||||
props = reactive(propValue)
|
||||
}
|
||||
emits('register', setProps, pagingRef, dataList)
|
||||
emits('register', setProps, pagingRef)
|
||||
|
||||
async function query(pageNo: number, pageSize: number) {
|
||||
if (props.query) {
|
||||
@ -67,7 +68,4 @@ function changeSearch(e: string) {
|
||||
}
|
||||
}
|
||||
|
||||
// 控制暂无数据图片显示
|
||||
const showNoDataImage = computed(() => dataList.value.length === 0)
|
||||
|
||||
</script>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import {isFunction} from "lodash";
|
||||
import {Ref, ref, nextTick} from "vue";
|
||||
import {Ref} from "vue";
|
||||
import {hideLoading, showLoading} from "@/utils/uniapp";
|
||||
import type {
|
||||
LayoutCallback,
|
||||
@ -13,46 +13,22 @@ import type {
|
||||
export function useLayout(options: LayoutOptions): UseLayoutInterfaceReturn {
|
||||
|
||||
let methods: Ref<PagingRefInterface>
|
||||
let dataListRef: Ref<any[]> | undefined
|
||||
|
||||
// 强制设置concat为false,使用完整数据模式
|
||||
if (!options.componentProps) options.componentProps = {};
|
||||
options.componentProps.concat = false;
|
||||
|
||||
// 用于维护所有已加载数据
|
||||
const allData = ref<any[]>([]);
|
||||
|
||||
async function requestApi(pageNo: number, pageSize: number) {
|
||||
if (isFunction(options.api)) {
|
||||
try {
|
||||
const result = await options.api(Object.assign({}, {
|
||||
pageNo: pageNo,
|
||||
pageSize: pageSize
|
||||
}, options.param))
|
||||
let params = Object.assign({}, {
|
||||
rows: pageSize,
|
||||
page: pageNo
|
||||
}, options.param)
|
||||
const result = await options.api(params)
|
||||
await nextTick()
|
||||
if (methods.value) {
|
||||
let newList = result[options.resultKey || 'rows'] || [];
|
||||
if (pageNo === 1) {
|
||||
allData.value = [...newList];
|
||||
if (dataListRef) dataListRef.value = allData.value;
|
||||
} else {
|
||||
// 合并去重
|
||||
const map = new Map();
|
||||
[...allData.value, ...newList].forEach(item => {
|
||||
map.set(item.id, item);
|
||||
});
|
||||
allData.value = Array.from(map.values());
|
||||
if (dataListRef) dataListRef.value = allData.value;
|
||||
}
|
||||
const hasMoreData = newList.length > 0;
|
||||
if (!hasMoreData) {
|
||||
await methods.value.completeByNoMore(allData.value as any, true);
|
||||
return;
|
||||
} else {
|
||||
await methods.value.complete(allData.value as any);
|
||||
}
|
||||
// @ts-ignore
|
||||
await methods.value.complete(result[options.resultKey || 'rows'])
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err', err)
|
||||
if (methods.value) {
|
||||
await methods.value.complete(false);
|
||||
}
|
||||
@ -64,9 +40,8 @@ export function useLayout(options: LayoutOptions): UseLayoutInterfaceReturn {
|
||||
options.query = requestApi
|
||||
}
|
||||
|
||||
const register = (callback: LayoutCallback, pagingRef: Ref<PagingRefInterface>, listRef?: Ref<any[]>) => {
|
||||
const register = (callback: LayoutCallback, pagingRef: Ref<PagingRefInterface>) => {
|
||||
methods = pagingRef
|
||||
dataListRef = listRef
|
||||
callback(options)
|
||||
}
|
||||
return [register,
|
||||
|
||||
@ -16,7 +16,6 @@ interface LayoutOptions {
|
||||
createdReload?: boolean //组件created时立即触发reload(可解决一些情况下先看到页面再看到loading的问题),auto为true时有效。为否时将在mounted+nextTick后触发reload
|
||||
autoCleanListWhenReload?: boolean //reload时立即自动清空原list,若立即自动清空,则在reload之后、请求回调之前页面是空白的
|
||||
fixed?: boolean //z-paging是否使用fixed布局,若使用fixed布局,则z-paging的父view无需固定高度,z-paging高度默认铺满屏幕,页面中的view请放在z-paging标签内,需要固定在顶部的view使用slot="top"包住,需要固定在底部的view使用slot="bottom"包住。
|
||||
concat?: boolean //自动拼接complete中传过来的数组
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -79,7 +79,7 @@ export default {
|
||||
minDate: {
|
||||
type: Number,
|
||||
// 最小默认值为前10年
|
||||
default: new Date(new Date().getFullYear() - 80, 0, 1).getTime()
|
||||
default: new Date(new Date().getFullYear() - 10, 0, 1).getTime()
|
||||
},
|
||||
// 可选的最小小时,仅mode=time有效
|
||||
minHour: {
|
||||
|
||||
@ -407,7 +407,7 @@ export default {
|
||||
background: #FFF;
|
||||
margin: 10px 0;
|
||||
width: 90vw;
|
||||
height: 90vh;
|
||||
height: 88vh;
|
||||
align-self: center;
|
||||
// pointer-events:none;
|
||||
}
|
||||
|
||||
@ -170,10 +170,10 @@ export default {
|
||||
parentArr = [...parents]
|
||||
delete parentArr.children
|
||||
parentid.push(item[this.idKey]);
|
||||
// 保留所有原始字段,而不仅仅是 key 和 title
|
||||
const parentItem = { ...item };
|
||||
delete parentItem.children; // 移除 children 字段避免循环引用
|
||||
parentArr.push(parentItem);
|
||||
parentArr.push({
|
||||
[this.idKey]: item[this.idKey],
|
||||
[this.rangeKey]: item[this.rangeKey]
|
||||
})
|
||||
this._renderTreeList(item.children, rank + 1, parentid, parentArr);
|
||||
} else {
|
||||
this.treeList[this.treeList.length - 1].lastRank = true;
|
||||
|
||||
@ -4735,6 +4735,7 @@ function drawYAxis(series, opts, config, context) {
|
||||
let textAlign = yData.textAlign || "right";
|
||||
//画Y轴刻度及文案
|
||||
rangesFormat.forEach(function(item, index) {
|
||||
var label = opts.yAxis.format(item);
|
||||
var pos = points[index];
|
||||
context.beginPath();
|
||||
context.setFontSize(yAxisFontSize);
|
||||
@ -4764,7 +4765,7 @@ function drawYAxis(series, opts, config, context) {
|
||||
context.setTextAlign('center');
|
||||
tmpstrat = tStartLeft - yAxisWidth.width / 2
|
||||
}
|
||||
context.fillText(String(item), tmpstrat, pos + yAxisFontSize / 2 - 3 * opts.pix);
|
||||
context.fillText(String(label), tmpstrat, pos + yAxisFontSize / 2 - 3 * opts.pix);
|
||||
|
||||
} else if (yAxisWidth.position == 'right') {
|
||||
//画刻度线
|
||||
@ -4786,7 +4787,7 @@ function drawYAxis(series, opts, config, context) {
|
||||
context.setTextAlign('center');
|
||||
tmpstrat = tStartRight + yAxisWidth.width / 2
|
||||
}
|
||||
context.fillText(String(item), tmpstrat, pos + yAxisFontSize / 2 - 3 * opts.pix);
|
||||
context.fillText(String(label), tmpstrat, pos + yAxisFontSize / 2 - 3 * opts.pix);
|
||||
} else if (yAxisWidth.position == 'center') {
|
||||
//画刻度线
|
||||
if (yData.calibration == true) {
|
||||
@ -4808,7 +4809,7 @@ function drawYAxis(series, opts, config, context) {
|
||||
context.setTextAlign('center');
|
||||
tmpstrat = tStartCenter - yAxisWidth.width / 2
|
||||
}
|
||||
context.fillText(String(item), tmpstrat, pos + yAxisFontSize / 2 - 3 * opts.pix);
|
||||
context.fillText(String(label), tmpstrat, pos + yAxisFontSize / 2 - 3 * opts.pix);
|
||||
}
|
||||
context.closePath();
|
||||
context.stroke();
|
||||
@ -7016,7 +7017,10 @@ var uCharts = function uCharts(opts) {
|
||||
dashLength: 4 * opts.pix,
|
||||
gridColor: '#cccccc',
|
||||
padding: 10,
|
||||
fontColor: '#666666'
|
||||
fontColor: '#666666',
|
||||
format: function format(val) {
|
||||
return val;
|
||||
}
|
||||
}, opts.yAxis);
|
||||
opts.xAxis = assign({}, {
|
||||
rotateLabel: false,
|
||||
|
||||
@ -1,214 +1,116 @@
|
||||
<template>
|
||||
<BasicLayout>
|
||||
<view class="teaching-resource-page">
|
||||
<!-- 主要内容区域 -->
|
||||
<view class="main-content">
|
||||
<!-- 左侧课程列表 -->
|
||||
<view class="left-panel">
|
||||
<scroll-view class="subject-list" scroll-y="true" show-scrollbar="false">
|
||||
<view
|
||||
class="subject-item"
|
||||
v-for="(subject, index) in subjectList"
|
||||
:key="subject.id"
|
||||
:class="{ active: selectedSubjectIndex === index }"
|
||||
@click="selectSubject(index)"
|
||||
>
|
||||
<text class="subject-name">{{ subject.name }}</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 右侧内容区域 -->
|
||||
<view class="right-panel">
|
||||
<view class="resource-section">
|
||||
<view class="section-title">科目</view>
|
||||
<view class="type-grid">
|
||||
<view class="type-item" :class="{ active: curType && curType.key === type.key }" v-for="(type, index) in typeTree" :key="index"
|
||||
@click="selectType(type)">
|
||||
<text class="type-text">{{ type.title }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="resource-section" v-if="curType && curType.children && curType.children.length > 0">
|
||||
<view class="section-title">年级</view>
|
||||
<view class="type-grid">
|
||||
<view class="type-item" :class="{ active: curNj && curNj.key === type.key }" v-for="(type, index) in curType.children" :key="index"
|
||||
@click="selectNj(type)">
|
||||
<text class="type-text">{{ type.title }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="resource-section" v-if="curNj && curNj.children && curNj.children.length > 0">
|
||||
<view class="section-title">上下册</view>
|
||||
<view class="type-grid">
|
||||
<view class="type-item" :class="{ active: curCe && curCe.key === type.key }" v-for="(type, index) in curNj.children" :key="index"
|
||||
@click="selectCe(type)">
|
||||
<text class="type-text">{{ type.title }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 资源类型 -->
|
||||
<view class="resource-section" v-if="currentSubject.resourceTypes && currentSubject.resourceTypes.length > 0">
|
||||
<view class="resource-section">
|
||||
<view class="section-title">资源类型</view>
|
||||
<view class="type-grid">
|
||||
<view
|
||||
class="type-item"
|
||||
v-for="(type, index) in currentSubject.resourceTypes"
|
||||
:key="index"
|
||||
@click="goToResourceList('type', type)"
|
||||
>
|
||||
<text class="type-text">{{ type }}</text>
|
||||
<view class="type-item" :class="{ active: curCategory && curCategory.key === type.key }" v-for="(type, index) in categoryList" :key="index"
|
||||
@click="selectCategory(type)">
|
||||
<text class="type-text">{{ type.label }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 年级选择 -->
|
||||
<view class="grade-section" v-if="currentSubject.grades && currentSubject.grades.length > 0">
|
||||
<view class="section-title">年级</view>
|
||||
<view class="grade-grid">
|
||||
<view
|
||||
class="grade-item"
|
||||
v-for="(grade, index) in currentSubject.grades"
|
||||
:key="index"
|
||||
@click="goToResourceList('grade', grade)"
|
||||
>
|
||||
<text class="grade-text">{{ grade }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view class="empty-state" v-if="!currentSubject.name">
|
||||
<text class="empty-text">请从左侧选择学科</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<template #bottom>
|
||||
<view class="white-bg-color py-5">
|
||||
<view class="flex-row items-center pb-10 pt-5">
|
||||
<u-button text="查询" class="mx-15" type="primary" @click="goTo"/>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</BasicLayout>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, computed, onMounted } from "vue";
|
||||
import { typesFindTreeApi } from "@/api/base/server";
|
||||
import { useDataStore } from "@/store/modules/data";
|
||||
const { setData } = useDataStore();
|
||||
|
||||
// 定义数据接口
|
||||
interface Subject {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
resourceTypes?: string[];
|
||||
grades?: string[];
|
||||
}
|
||||
const typeTree = ref<any>([]);
|
||||
|
||||
// 响应式数据
|
||||
const selectedSubjectIndex = ref(1); // 默认选中数学
|
||||
|
||||
// 模拟课程数据
|
||||
const subjectList = reactive<Subject[]>([
|
||||
{
|
||||
id: 'chinese',
|
||||
name: '语文',
|
||||
description: '语言文字运用与文学鉴赏',
|
||||
resourceTypes: ['课件', '教案', '学案', '作业', '试卷'],
|
||||
grades: ['一年级', '二年级', '三年级', '四年级', '五年级', '六年级']
|
||||
},
|
||||
{
|
||||
id: 'math',
|
||||
name: '数学',
|
||||
description: '数学思维与逻辑推理',
|
||||
resourceTypes: ['题集', '素材', '备课综合'],
|
||||
grades: ['一年级', '二年级', '三年级', '四年级', '五年级', '六年级']
|
||||
},
|
||||
{
|
||||
id: 'english',
|
||||
name: '英语',
|
||||
description: '英语听说读写综合能力',
|
||||
resourceTypes: ['课件', '音频', '视频', '练习'],
|
||||
grades: ['一年级', '二年级', '三年级', '四年级', '五年级', '六年级']
|
||||
},
|
||||
{
|
||||
id: 'moral',
|
||||
name: '道德与法治',
|
||||
description: '品德修养与法律意识',
|
||||
resourceTypes: [],
|
||||
grades: ['一年级', '二年级', '三年级', '四年级', '五年级', '六年级']
|
||||
},
|
||||
{
|
||||
id: 'science',
|
||||
name: '科学',
|
||||
description: '科学探究与实验操作',
|
||||
resourceTypes: ['实验', '课件', '视频'],
|
||||
grades: ['一年级', '二年级', '三年级', '四年级', '五年级', '六年级']
|
||||
},
|
||||
{
|
||||
id: 'it',
|
||||
name: '信息科技',
|
||||
description: '信息技术与编程思维',
|
||||
resourceTypes: ['软件', '教程', '项目'],
|
||||
grades: ['一年级', '二年级', '三年级', '四年级', '五年级', '六年级']
|
||||
},
|
||||
{
|
||||
id: 'music',
|
||||
name: '音乐',
|
||||
description: '音乐欣赏与艺术表现',
|
||||
resourceTypes: ['音频', '乐谱', '视频'],
|
||||
grades: ['一年级', '二年级', '三年级', '四年级', '五年级', '六年级']
|
||||
},
|
||||
{
|
||||
id: 'art',
|
||||
name: '美术',
|
||||
description: '美术创作与艺术鉴赏',
|
||||
resourceTypes: ['图片', '视频', '作品'],
|
||||
grades: ['一年级', '二年级', '三年级', '四年级', '五年级', '六年级']
|
||||
},
|
||||
{
|
||||
id: 'pe',
|
||||
name: '体育',
|
||||
description: '体育运动与健康生活',
|
||||
resourceTypes: ['视频', '规则', '训练'],
|
||||
grades: ['一年级', '二年级', '三年级', '四年级', '五年级', '六年级']
|
||||
},
|
||||
{
|
||||
id: 'labor',
|
||||
name: '劳动技术',
|
||||
description: '劳动实践与技能培养',
|
||||
resourceTypes: ['教程', '工具', '项目'],
|
||||
grades: ['一年级', '二年级', '三年级', '四年级', '五年级', '六年级']
|
||||
},
|
||||
{
|
||||
id: 'expand',
|
||||
name: '拓展',
|
||||
description: '综合素质拓展活动',
|
||||
resourceTypes: ['活动', '方案', '素材'],
|
||||
grades: ['一年级', '二年级', '三年级', '四年级', '五年级', '六年级']
|
||||
},
|
||||
{
|
||||
id: 'psychology',
|
||||
name: '心理健康',
|
||||
description: '心理健康与情感教育',
|
||||
resourceTypes: ['课件', '测试', '案例'],
|
||||
grades: ['一年级', '二年级', '三年级', '四年级', '五年级', '六年级']
|
||||
},
|
||||
{
|
||||
id: 'practice',
|
||||
name: '综合实践',
|
||||
description: '综合实践活动课程',
|
||||
resourceTypes: ['方案', '案例', '工具'],
|
||||
grades: ['一年级', '二年级', '三年级', '四年级', '五年级', '六年级']
|
||||
},
|
||||
{
|
||||
id: 'calligraphy',
|
||||
name: '书法',
|
||||
description: '书法艺术与汉字文化',
|
||||
resourceTypes: ['字帖', '视频', '作品'],
|
||||
grades: ['一年级', '二年级', '三年级', '四年级', '五年级', '六年级']
|
||||
}
|
||||
const categoryList = ref([
|
||||
{ key: '', label: '不限' },
|
||||
{ key: '1', label: '课件' },
|
||||
{ key: '2', label: '教案' },
|
||||
{ key: '3', label: '学案' },
|
||||
{ key: '4', label: '作业' },
|
||||
{ key: '5', label: '试卷' },
|
||||
{ key: '6', label: '教材' },
|
||||
{ key: '7', label: '示范课' },
|
||||
{ key: '8', label: '音视频合集' }
|
||||
]);
|
||||
|
||||
// 计算属性
|
||||
const currentSubject = computed(() => {
|
||||
return subjectList[selectedSubjectIndex.value] || {};
|
||||
});
|
||||
const curType = ref<any>();
|
||||
const curNj = ref<any>();
|
||||
const curCe = ref<any>();
|
||||
const curCategory = ref<any>();
|
||||
|
||||
const selectType = (type: any) => {
|
||||
curType.value = type;
|
||||
curNj.value = curType.value.children[0];
|
||||
curCe.value = curNj.value.children[0];
|
||||
}
|
||||
const selectNj = (type: any) => {
|
||||
curNj.value = type;
|
||||
curCe.value = curNj.value.children[0];
|
||||
}
|
||||
const selectCe = (type: any) => {
|
||||
curCe.value = type;
|
||||
}
|
||||
|
||||
const selectCategory = (type: any) => {
|
||||
curCategory.value = type;
|
||||
}
|
||||
|
||||
// 方法
|
||||
const selectSubject = (index: number) => {
|
||||
selectedSubjectIndex.value = index;
|
||||
};
|
||||
|
||||
// 跳转到资源列表页面
|
||||
const goToResourceList = (filterType: string, filterValue: string) => {
|
||||
const subject = currentSubject.value;
|
||||
const params = {
|
||||
subjectId: subject.id,
|
||||
subjectName: subject.name,
|
||||
filterType: filterType,
|
||||
filterValue: filterValue
|
||||
};
|
||||
|
||||
const queryString = Object.entries(params).map(([key, value]) => `${key}=${encodeURIComponent(value)}`).join('&');
|
||||
|
||||
uni.navigateTo({
|
||||
url: `/pages/view/routine/JiaoXueZiYuan/indexList?${queryString}`
|
||||
const goTo = function () {
|
||||
setData({
|
||||
resourceType: curCe.value.key,
|
||||
category: curCategory.value.key,
|
||||
});
|
||||
};
|
||||
uni.navigateTo({
|
||||
url: `/pages/view/routine/JiaoXueZiYuan/indexList`
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
// 页面加载完成后的初始化操作
|
||||
console.log('教学资源页面加载完成');
|
||||
// 页面加载完成后的初始化操作
|
||||
onMounted(async () => {
|
||||
const res = await typesFindTreeApi();
|
||||
typeTree.value = res.result || [];
|
||||
console.log('教学资源页面加载完成', res);
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -232,33 +134,33 @@ onMounted(() => {
|
||||
width: 280rpx;
|
||||
background: #ffffff;
|
||||
border-right: 1px solid #e5e5e5;
|
||||
|
||||
|
||||
.subject-list {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
.subject-item {
|
||||
padding: 30rpx 20rpx;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
text-align: center;
|
||||
|
||||
|
||||
.subject-name {
|
||||
font-size: 28rpx;
|
||||
color: #666666;
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
&.active {
|
||||
background: #fff3e0;
|
||||
|
||||
|
||||
.subject-name {
|
||||
color: #ff9800;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&:hover:not(.active) {
|
||||
background: #f8f9fa;
|
||||
}
|
||||
@ -280,7 +182,7 @@ onMounted(() => {
|
||||
.grade-section {
|
||||
margin-bottom: 40rpx;
|
||||
flex-shrink: 0;
|
||||
|
||||
|
||||
.section-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
@ -304,16 +206,16 @@ onMounted(() => {
|
||||
border-radius: 8rpx;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
|
||||
.type-text {
|
||||
font-size: 28rpx;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
||||
&.active {
|
||||
border-color: #ff9800;
|
||||
background: #fff3e0;
|
||||
|
||||
|
||||
.type-text {
|
||||
color: #ff9800;
|
||||
}
|
||||
@ -335,16 +237,16 @@ onMounted(() => {
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
text-align: center;
|
||||
|
||||
|
||||
.grade-text {
|
||||
font-size: 28rpx;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
|
||||
&:hover {
|
||||
border-color: #ff9800;
|
||||
background: #fff3e0;
|
||||
|
||||
|
||||
.grade-text {
|
||||
color: #ff9800;
|
||||
}
|
||||
@ -357,7 +259,7 @@ onMounted(() => {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
color: #999999;
|
||||
@ -369,25 +271,25 @@ onMounted(() => {
|
||||
.left-panel {
|
||||
width: 150rpx;
|
||||
}
|
||||
|
||||
|
||||
.subject-item {
|
||||
padding: 20rpx 10rpx;
|
||||
|
||||
|
||||
.subject-name {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.right-panel {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
|
||||
.tag-item {
|
||||
padding: 10rpx 18rpx;
|
||||
|
||||
|
||||
.tag-text {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
@ -1,468 +1,287 @@
|
||||
<template>
|
||||
<BasicListLayout
|
||||
:show-nav-bar="true"
|
||||
:nav-bar-props="{ title: '教学资源' }"
|
||||
@register="register"
|
||||
>
|
||||
<template #top>
|
||||
<view class="search-section">
|
||||
<view class="search-box">
|
||||
<uni-icons type="search" size="18" color="#999"></uni-icons>
|
||||
<input
|
||||
class="search-input"
|
||||
type="text"
|
||||
placeholder="搜索教学资源..."
|
||||
v-model="searchKeyword"
|
||||
@input="onSearchInput"
|
||||
@confirm="onSearchConfirm"
|
||||
/>
|
||||
<view class="search-clear" v-if="searchKeyword" @click="clearSearch">
|
||||
<uni-icons type="clear" size="16" color="#999"></uni-icons>
|
||||
</view>
|
||||
<BasicListLayout :show-nav-bar="true" :nav-bar-props="{ title: '教学资源' }" @register="register">
|
||||
<template #top>
|
||||
<view class="search-section">
|
||||
<view class="search-box">
|
||||
<uni-icons type="search" size="18" color="#999"></uni-icons>
|
||||
<input class="search-input" type="text" placeholder="搜索资源名称" v-model="searchKeyword" />
|
||||
<view class="search-clear" v-if="searchKeyword" @click="clearSearch">
|
||||
<uni-icons type="clear" size="16" color="#999"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<template #default="{ list }">
|
||||
<view class="list-container">
|
||||
<!-- Add @click handler to navigate -->
|
||||
<view class="resource-item" v-for="item in list" :key="item.id" @click="goToDetail(item.id)">
|
||||
<view class="item-icon-container">
|
||||
<view class="item-icon">{{ item.iconLetter }}</view>
|
||||
<text class="item-pages">-{{ item.pages }}页-</text>
|
||||
</view>
|
||||
<view class="item-details">
|
||||
<text class="item-title">{{ item.title }}</text>
|
||||
<!-- 标签区域 -->
|
||||
<view class="tags-container" v-if="item.tags && item.tags.length > 0">
|
||||
<view class="tag-item" v-for="tag in item.tags" :key="tag">{{ tag }}</view>
|
||||
</view>
|
||||
<view class="item-meta">
|
||||
<text class="meta-text">{{ item.publishDate }}</text>
|
||||
<text class="meta-text">浏览量: {{ item.views }}</text>
|
||||
<text class="meta-text">下载量: {{ item.downloads }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
</BasicListLayout>
|
||||
|
||||
<!-- Filter Popup -->
|
||||
<uni-popup ref="filterPopupRef" type="bottom" background-color="#fff">
|
||||
<view class="popup-content">
|
||||
<view class="popup-header">
|
||||
<text>{{ currentFilterTitle }}</text>
|
||||
<uni-icons type="closeempty" size="20" @click="closeFilterPopup"></uni-icons>
|
||||
</view>
|
||||
<scroll-view scroll-y class="popup-options">
|
||||
<view
|
||||
class="option-item"
|
||||
v-for="option in currentFilterOptions"
|
||||
:key="option.id ?? 'null'"
|
||||
:class="{ active: isOptionSelected(option) }"
|
||||
@click="selectFilterOption(option)"
|
||||
>
|
||||
{{ option.name }}
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from "vue";
|
||||
import { useLayout } from "@/components/BasicListLayout/hooks/useLayout";
|
||||
|
||||
interface Resource {
|
||||
id: number;
|
||||
iconLetter: string;
|
||||
title: string;
|
||||
pages: number;
|
||||
publishDate: string;
|
||||
views: number;
|
||||
downloads: number;
|
||||
tags: string[];
|
||||
}
|
||||
|
||||
interface FilterOption {
|
||||
id: string | number | null;
|
||||
name: string;
|
||||
}
|
||||
|
||||
// --- Filter Data (Mock) ---
|
||||
const directories = ref<FilterOption[]>([
|
||||
{ id: null, name: '全部目录' },
|
||||
{ id: 'd1', name: '数学教案' },
|
||||
{ id: 'd2', name: '语文课件' },
|
||||
{ id: 'd3', name: '英语练习' },
|
||||
{ id: 'd4', name: '科学实验' },
|
||||
]);
|
||||
|
||||
const types1 = ref<FilterOption[]>([
|
||||
{ id: null, name: '全部类型1' },
|
||||
{ id: 't1-1', name: '课件PPT' },
|
||||
{ id: 't1-2', name: '教学视频' },
|
||||
{ id: 't1-3', name: 'Word文档' },
|
||||
]);
|
||||
|
||||
const types2 = ref<FilterOption[]>([
|
||||
{ id: null, name: '全部类型2' },
|
||||
{ id: 't2-1', name: '期中' },
|
||||
{ id: 't2-2', name: '期末' },
|
||||
{ id: 't2-3', name: '单元测试' },
|
||||
]);
|
||||
|
||||
// --- Search State ---
|
||||
const searchKeyword = ref<string>('');
|
||||
|
||||
// --- Filter State ---
|
||||
const selectedDirectory = ref<FilterOption | null>(directories.value[0]);
|
||||
const selectedType1 = ref<FilterOption | null>(types1.value[0]);
|
||||
const selectedType2 = ref<FilterOption | null>(types2.value[0]);
|
||||
const filterPopupRef = ref<any>(null);
|
||||
const currentFilterType = ref<'directory' | 'type1' | 'type2' | null>(null);
|
||||
|
||||
// --- Computed Properties for Popup ---
|
||||
const currentFilterOptions = computed(() => {
|
||||
switch (currentFilterType.value) {
|
||||
case 'directory': return directories.value;
|
||||
case 'type1': return types1.value;
|
||||
case 'type2': return types2.value;
|
||||
default: return [];
|
||||
}
|
||||
});
|
||||
|
||||
const currentFilterTitle = computed(() => {
|
||||
switch (currentFilterType.value) {
|
||||
case 'directory': return '选择目录';
|
||||
case 'type1': return '选择类型1';
|
||||
case 'type2': return '选择类型2';
|
||||
default: return '选择选项';
|
||||
}
|
||||
});
|
||||
|
||||
const isOptionSelected = (option: FilterOption) => {
|
||||
switch (currentFilterType.value) {
|
||||
case 'directory': return selectedDirectory.value?.id === option.id;
|
||||
case 'type1': return selectedType1.value?.id === option.id;
|
||||
case 'type2': return selectedType2.value?.id === option.id;
|
||||
default: return false;
|
||||
}
|
||||
};
|
||||
|
||||
// --- Mock API (Changed return type to Promise<any>) ---
|
||||
const testList = async (params: any): Promise<any> => {
|
||||
console.log('API called with params:', params);
|
||||
const page = params.page || 1;
|
||||
const pageSize = params.pageSize || 10;
|
||||
|
||||
const allItems: Resource[] = Array.from({ length: 50 }).map((_, index) => {
|
||||
const id = index + 1;
|
||||
const directoryFilter = params.directoryId ? `[目录${params.directoryId}]` : '';
|
||||
const type1Filter = params.type1Id ? `[类型1-${params.type1Id}]` : '';
|
||||
const type2Filter = params.type2Id ? `[类型2-${params.type2Id}]` : '';
|
||||
|
||||
// 生成随机标签
|
||||
const subjectTags = ['语文', '数学', '英语', '科学', '历史'];
|
||||
const gradeTags = ['一年级', '二年级', '三年级', '四年级', '五年级', '六年级'];
|
||||
const termTags = ['上册', '下册'];
|
||||
const typeTags = ['练习题', '课件', '教案', '测试卷'];
|
||||
|
||||
const tags = [
|
||||
subjectTags[id % subjectTags.length],
|
||||
gradeTags[id % gradeTags.length],
|
||||
termTags[id % termTags.length],
|
||||
...(id % 3 === 0 ? [typeTags[id % typeTags.length]] : [])
|
||||
];
|
||||
|
||||
return {
|
||||
id: id,
|
||||
iconLetter: 'W',
|
||||
title: `专题${String(id).padStart(2, '0')}${directoryFilter}${type1Filter}${type2Filter} (突破)`,
|
||||
pages: 30 + (id % 15),
|
||||
publishDate: `0${1 + (id % 9)}月${10 + (id % 20)}日发布`,
|
||||
views: 1500 + (id * 17 % 500),
|
||||
downloads: 50 + (id * 7 % 40),
|
||||
tags: tags,
|
||||
};
|
||||
});
|
||||
|
||||
let filteredItems = allItems;
|
||||
|
||||
// 搜索关键词过滤
|
||||
if (params.keyword) {
|
||||
filteredItems = filteredItems.filter(item =>
|
||||
item.title.toLowerCase().includes(params.keyword.toLowerCase())
|
||||
);
|
||||
}
|
||||
|
||||
if (params.directoryId) {
|
||||
filteredItems = filteredItems.filter(item => item.title.includes(`[目录${params.directoryId}]`));
|
||||
}
|
||||
if (params.type1Id) {
|
||||
filteredItems = filteredItems.filter(item => item.title.includes(`[类型1-${params.type1Id}]`));
|
||||
}
|
||||
if (params.type2Id) {
|
||||
filteredItems = filteredItems.filter(item => item.title.includes(`[类型2-${params.type2Id}]`));
|
||||
}
|
||||
|
||||
const totalFilteredItems = filteredItems.length;
|
||||
const paginatedItems = filteredItems.slice((page - 1) * pageSize, page * pageSize);
|
||||
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
// Return structure expected by useLayout
|
||||
resolve({ message: "成功", resultCode: 200, rows: paginatedItems, total: totalFilteredItems });
|
||||
}, 300);
|
||||
});
|
||||
};
|
||||
|
||||
// --- Layout Hook (Removed 'immediate' from componentProps) ---
|
||||
const [register, { reload, setParam }] = useLayout({
|
||||
api: testList,
|
||||
componentProps: {
|
||||
// No problematic props
|
||||
},
|
||||
});
|
||||
|
||||
// --- Search Methods ---
|
||||
const onSearchInput = () => {
|
||||
setParam({ keyword: searchKeyword.value });
|
||||
};
|
||||
|
||||
const onSearchConfirm = () => {
|
||||
setParam({ keyword: searchKeyword.value });
|
||||
};
|
||||
|
||||
const clearSearch = () => {
|
||||
searchKeyword.value = '';
|
||||
setParam({ keyword: '' });
|
||||
};
|
||||
<!-- 增加一个搜索按钮 -->
|
||||
<u-button text="搜索" class="search-btn" type="primary" @click="onSearchConfirm"/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
// --- Navigation ---
|
||||
const goToDetail = (id: number) => {
|
||||
uni.navigateTo({
|
||||
url: `./detail?id=${id}` // Navigate to detail page in the same directory
|
||||
});
|
||||
};
|
||||
|
||||
// --- Filter Popup Methods ---
|
||||
const openFilterPopup = (type: 'directory' | 'type1' | 'type2') => {
|
||||
currentFilterType.value = type;
|
||||
filterPopupRef.value?.open();
|
||||
};
|
||||
|
||||
const closeFilterPopup = () => {
|
||||
filterPopupRef.value?.close();
|
||||
};
|
||||
|
||||
const selectFilterOption = (option: FilterOption) => {
|
||||
switch (currentFilterType.value) {
|
||||
case 'directory':
|
||||
selectedDirectory.value = option;
|
||||
setParam({ directoryId: option.id });
|
||||
break;
|
||||
case 'type1':
|
||||
selectedType1.value = option;
|
||||
setParam({ type1Id: option.id });
|
||||
break;
|
||||
case 'type2':
|
||||
selectedType2.value = option;
|
||||
setParam({ type2Id: option.id });
|
||||
break;
|
||||
}
|
||||
closeFilterPopup();
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.search-section {
|
||||
padding: 20rpx 30rpx;
|
||||
background-color: #ffffff;
|
||||
border-bottom: 1rpx solid #e0e0e0;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
|
||||
.search-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 50rpx;
|
||||
padding: 0 20rpx;
|
||||
height: 70rpx;
|
||||
|
||||
uni-icons {
|
||||
margin-right: 15rpx;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
border: none;
|
||||
background: transparent;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
|
||||
&::placeholder {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.search-clear {
|
||||
margin-left: 15rpx;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.list-container {
|
||||
background-color: #f4f5f7;
|
||||
/* Add padding-top to prevent content from hiding behind sticky filter */
|
||||
/* Adjust value based on filter-section height */
|
||||
}
|
||||
|
||||
.resource-item {
|
||||
<template #default="{ data }">
|
||||
<view class="list-container">
|
||||
<!-- Add @click handler to navigate -->
|
||||
<view class="resource-item" @click="goToDetail(data.id)">
|
||||
<view class="item-icon-container">
|
||||
<view class="item-icon">{{ data.resSuf }}</view>
|
||||
<!-- <text class="item-pages">-{{ item.pages }}页-</text> -->
|
||||
</view>
|
||||
<view class="item-details">
|
||||
<view class="item-title" v-if="data.resourName.includes('《') && data.resourName.includes('》')">{{ data.resourName }}{{ data.hour ? ' - ' + data.hour : '' }}</view>
|
||||
<view class="item-title" v-else>《{{ data.resourName }}》{{ data.hour ? ' - ' + data.hour : '' }}</view>
|
||||
<!-- 标签区域 -->
|
||||
<view class="tags-container" v-if="data.parentName && data.parentName.length > 0">
|
||||
<view class="tag-item" v-for="tag in data.parentName.split(',')" :key="tag">{{ tag }}</view>
|
||||
</view>
|
||||
<view class="item-meta">
|
||||
<text class="meta-text">{{ data.createdTime }}</text>
|
||||
<text class="meta-text">浏览量: {{ data.lookNum }}</text>
|
||||
<text class="meta-text">下载量: {{ data.downNum }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
</BasicListLayout>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useLayout } from "@/components/BasicListLayout/hooks/useLayout";
|
||||
import { resourcesFindPageApi } from "@/api/base/server";
|
||||
import { useDataStore } from "@/store/modules/data";
|
||||
const { getData } = useDataStore();
|
||||
|
||||
const buildParams = () => {
|
||||
setParam({ ...getData, ...{ keyword: searchKeyword.value } });
|
||||
reload();
|
||||
}
|
||||
|
||||
const searchKeyword = ref<string>('');
|
||||
|
||||
// --- Layout Hook (Removed 'immediate' from componentProps) ---
|
||||
const [register, { reload, setParam }] = useLayout({
|
||||
api: resourcesFindPageApi,
|
||||
componentProps: {
|
||||
defaultPageSize: 5, // 每页显示5条数据
|
||||
loadingMoreEnabled: true, // 启用加载更多
|
||||
},
|
||||
});
|
||||
|
||||
// --- Search Methods ---
|
||||
const onSearchConfirm = () => {
|
||||
buildParams();
|
||||
};
|
||||
|
||||
const clearSearch = () => {
|
||||
searchKeyword.value = '';
|
||||
buildParams();
|
||||
};
|
||||
|
||||
// --- Navigation ---
|
||||
const goToDetail = (id: number) => {
|
||||
uni.navigateTo({
|
||||
url: `./detail?id=${id}` // Navigate to detail page in the same directory
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
buildParams();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
.search-section {
|
||||
padding: 20rpx 30rpx;
|
||||
display: flex;
|
||||
background-color: #ffffff;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
margin-bottom: 6px;
|
||||
|
||||
.search-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #ffffff;
|
||||
border-radius: 16rpx;
|
||||
padding: 25rpx 20rpx;
|
||||
margin-bottom: 20rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
cursor: pointer; // Add cursor pointer to indicate clickability
|
||||
|
||||
.item-icon-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-right: 25rpx;
|
||||
flex-shrink: 0;
|
||||
|
||||
.item-icon {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
border-radius: 12rpx;
|
||||
background-color: #409eff;
|
||||
color: #ffffff;
|
||||
font-size: 40rpx;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.item-pages {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
}
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 50rpx;
|
||||
padding: 0 20rpx;
|
||||
height: 70rpx;
|
||||
flex: 1 0 1px;
|
||||
|
||||
uni-icons {
|
||||
margin-right: 15rpx;
|
||||
}
|
||||
|
||||
.item-details {
|
||||
|
||||
.search-input {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
|
||||
.item-title {
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
margin-bottom: 15rpx;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.tags-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10rpx;
|
||||
margin-bottom: 15rpx;
|
||||
|
||||
.tag-item {
|
||||
background-color: #f0f2f5;
|
||||
color: #666;
|
||||
font-size: 22rpx;
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
white-space: nowrap;
|
||||
border: 1rpx solid #e0e0e0;
|
||||
|
||||
&:first-child {
|
||||
background-color: #e7f4ff;
|
||||
color: #1890ff;
|
||||
border-color: #91d5ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 24rpx;
|
||||
height: 100%;
|
||||
border: none;
|
||||
background: transparent;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
|
||||
&::placeholder {
|
||||
color: #999;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.meta-text {
|
||||
margin-right: 15rpx;
|
||||
white-space: nowrap;
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-clear {
|
||||
margin-left: 15rpx;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.search-btn {
|
||||
margin-left: 10px;
|
||||
flex: 0 0 80px;
|
||||
height: 35px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.list-container {
|
||||
background-color: #f4f5f7;
|
||||
/* Add padding-top to prevent content from hiding behind sticky filter */
|
||||
/* Adjust value based on filter-section height */
|
||||
}
|
||||
|
||||
.resource-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #ffffff;
|
||||
border-radius: 16rpx;
|
||||
padding: 25rpx 20rpx;
|
||||
margin-bottom: 20rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
cursor: pointer; // Add cursor pointer to indicate clickability
|
||||
|
||||
.item-icon-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-right: 25rpx;
|
||||
flex-shrink: 0;
|
||||
|
||||
.item-icon {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
line-height: 160rpx;
|
||||
border-radius: 12rpx;
|
||||
background-color: #409eff;
|
||||
color: #ffffff;
|
||||
font-size: 40rpx;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.item-pages {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.item-details {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
|
||||
.item-title {
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
margin-bottom: 15rpx;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.tags-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10rpx;
|
||||
margin-bottom: 15rpx;
|
||||
|
||||
.tag-item {
|
||||
background-color: #f0f2f5;
|
||||
color: #666;
|
||||
font-size: 22rpx;
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
white-space: nowrap;
|
||||
border: 1rpx solid #e0e0e0;
|
||||
|
||||
&:first-child {
|
||||
background-color: #e7f4ff;
|
||||
color: #1890ff;
|
||||
border-color: #91d5ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.meta-text {
|
||||
margin-right: 15rpx;
|
||||
white-space: nowrap;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Popup Styles
|
||||
.popup-content {
|
||||
background-color: #fff;
|
||||
border-top-left-radius: 20rpx;
|
||||
border-top-right-radius: 20rpx;
|
||||
padding: 20rpx;
|
||||
padding-bottom: 40rpx; // Add space at the bottom
|
||||
}
|
||||
|
||||
// Popup Styles
|
||||
.popup-content {
|
||||
background-color: #fff;
|
||||
border-top-left-radius: 20rpx;
|
||||
border-top-right-radius: 20rpx;
|
||||
padding: 20rpx;
|
||||
padding-bottom: 40rpx; // Add space at the bottom
|
||||
}
|
||||
|
||||
.popup-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 15rpx 10rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.popup-options {
|
||||
max-height: 60vh; // Limit popup height
|
||||
}
|
||||
|
||||
.option-item {
|
||||
padding: 25rpx 20rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
border-bottom: 1rpx solid #f5f5f5;
|
||||
cursor: pointer;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.popup-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 15rpx 10rpx;
|
||||
font-size: 32rpx;
|
||||
|
||||
&.active {
|
||||
color: #409eff; // Highlight selected item
|
||||
font-weight: bold;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.popup-options {
|
||||
max-height: 60vh; // Limit popup height
|
||||
|
||||
&:hover {
|
||||
background-color: #f9f9f9; // Subtle hover effect
|
||||
}
|
||||
|
||||
.option-item {
|
||||
padding: 25rpx 20rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
border-bottom: 1rpx solid #f5f5f5;
|
||||
cursor: pointer;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: #409eff; // Highlight selected item
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #f9f9f9; // Subtle hover effect
|
||||
}
|
||||
}
|
||||
</style>
|
||||
}
|
||||
</style>
|
||||
Loading…
x
Reference in New Issue
Block a user