|
@@ -0,0 +1,235 @@
|
|
|
+<template>
|
|
|
+ <view class="skill-container">
|
|
|
+ <!-- 技能块展示 -->
|
|
|
+ <view class="skill-list">
|
|
|
+ <view v-for="item in displayedList" :key="item.id" class="skill-block"
|
|
|
+ :class="{ selected: isSelected(item.id) }" @click="toggleSelect(item)">
|
|
|
+ {{ item.name }}
|
|
|
+ </view>
|
|
|
+ <!-- 添加按钮 -->
|
|
|
+ <view v-if="showAddButton" class="add-block" @click="handleAdd">
|
|
|
+ + 添加
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 展开/收起按钮 -->
|
|
|
+ <view v-if="showExpandButton" class="expand-button" @click="toggleExpand">
|
|
|
+ {{ showAll ? '收起' : `展开` }}
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- <view v-if="showExpandButton" class="expand-button" @click="toggleExpand">
|
|
|
+ {{ showAll ? '收起' : `展开剩余${remainingCount}项` }}
|
|
|
+ </view> -->
|
|
|
+
|
|
|
+ <!-- 添加弹窗 -->
|
|
|
+ <uni-popup ref="addPopup" type="dialog">
|
|
|
+ <view class="add-popup">
|
|
|
+ <input v-model="newName" placeholder="请输入技能名称" class="add-input" />
|
|
|
+ <view class="button-group">
|
|
|
+ <button @click="confirmAdd" class="confirm-button">确认</button>
|
|
|
+ <button @click="cancelAdd" class="cancel-button">取消</button>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </uni-popup>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+ export default {
|
|
|
+ name: 'SkillSelector',
|
|
|
+ props: {
|
|
|
+ // 技能列表(必须包含id和name字段)
|
|
|
+ list: {
|
|
|
+ type: Array,
|
|
|
+ required: true,
|
|
|
+ default: () => []
|
|
|
+ },
|
|
|
+ // 默认显示数量
|
|
|
+ defaultCount: {
|
|
|
+ type: Number,
|
|
|
+ default: 10
|
|
|
+ },
|
|
|
+ // 是否显示添加功能
|
|
|
+ showAdd: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true
|
|
|
+ },
|
|
|
+ // 新增模式选择
|
|
|
+ mode: {
|
|
|
+ type: String,
|
|
|
+ default: 'multiple', // 'single' | 'multiple'
|
|
|
+ validator: (value) => ['single', 'multiple'].includes(value)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ showAll: false,
|
|
|
+ selectedData: [],
|
|
|
+ newName: ''
|
|
|
+ };
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ displayedList() {
|
|
|
+ return this.showAll ? this.list : this.list.slice(0, this.defaultCount);
|
|
|
+ },
|
|
|
+ remainingCount() {
|
|
|
+ return this.list.length - this.defaultCount;
|
|
|
+ },
|
|
|
+ showExpandButton() {
|
|
|
+ return this.list.length > this.defaultCount;
|
|
|
+ },
|
|
|
+ showAddButton() {
|
|
|
+ if (!this.showAdd) return false;
|
|
|
+ return this.showAll || this.list.length < this.defaultCount;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ isSelected(id) {
|
|
|
+ return this.selectedData.some(item => item.id === id);
|
|
|
+ },
|
|
|
+ // toggleSelect(data) {
|
|
|
+ // const index = this.selectedData.indexOf(data);
|
|
|
+ // console.log('index', index);
|
|
|
+ // if (index == -1) {
|
|
|
+ // this.selectedData.push(data);
|
|
|
+ // } else {
|
|
|
+ // this.selectedData.splice(index, 1);
|
|
|
+ // }
|
|
|
+
|
|
|
+ // console.log('this.selectedData', this.selectedData);
|
|
|
+ // this.$emit('change', this.selectedData);
|
|
|
+ // },
|
|
|
+
|
|
|
+ toggleSelect(data) {
|
|
|
+ if (this.mode == 'single') {
|
|
|
+ this.handleSingleSelect(data);
|
|
|
+ } else {
|
|
|
+ this.handleMultipleSelect(data);
|
|
|
+ }
|
|
|
+ this.$emit('change', this.selectedData);
|
|
|
+ },
|
|
|
+ // 单选处理逻辑
|
|
|
+ handleSingleSelect(data) {
|
|
|
+ const isSelected = this.selectedData.some(item => item.id == data.id);
|
|
|
+ if (isSelected) {
|
|
|
+ // 取消选择
|
|
|
+ this.selectedData = [];
|
|
|
+ } else {
|
|
|
+ // 替换选择
|
|
|
+ this.selectedData = [data];
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 多选处理逻辑
|
|
|
+ handleMultipleSelect(data) {
|
|
|
+ const index = this.selectedData.findIndex(item => item.id == data.id);
|
|
|
+ if (index === -1) {
|
|
|
+ this.selectedData.push(data);
|
|
|
+ } else {
|
|
|
+ this.selectedData.splice(index, 1);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ toggleExpand() {
|
|
|
+ this.showAll = !this.showAll;
|
|
|
+ },
|
|
|
+
|
|
|
+ handleAdd() {
|
|
|
+ this.$refs.addPopup.open();
|
|
|
+ },
|
|
|
+
|
|
|
+ confirmAdd() {
|
|
|
+ if (!this.newName.trim()) {
|
|
|
+ uni.showToast({
|
|
|
+ title: '请输入技能名称',
|
|
|
+ icon: 'none'
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const newObject = {
|
|
|
+ id: this.list.length, // 使用时间戳作为临时ID
|
|
|
+ name: this.newName
|
|
|
+ };
|
|
|
+ console.log('list', this.list);
|
|
|
+ console.log('newObject', newObject);
|
|
|
+
|
|
|
+ this.$emit('add', newObject);
|
|
|
+ this.newName = '';
|
|
|
+ this.$refs.addPopup.close();
|
|
|
+ },
|
|
|
+
|
|
|
+ cancelAdd() {
|
|
|
+ this.newName = '';
|
|
|
+ this.$refs.addPopup.close();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+ .skill-container {
|
|
|
+ padding: 20rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .skill-list {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 20rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .skill-block {
|
|
|
+ padding: 12rpx 24rpx;
|
|
|
+ background: #f5f5f5;
|
|
|
+ border-radius: 8rpx;
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #333;
|
|
|
+ }
|
|
|
+
|
|
|
+ .skill-block.selected {
|
|
|
+ background: #007aff;
|
|
|
+ color: #fff;
|
|
|
+ }
|
|
|
+
|
|
|
+ .add-block {
|
|
|
+ background: transparent;
|
|
|
+ border: 1px dashed #007aff;
|
|
|
+ color: #007aff;
|
|
|
+ }
|
|
|
+
|
|
|
+ .expand-button {
|
|
|
+ margin-top: 30rpx;
|
|
|
+ color: #007aff;
|
|
|
+ font-size: 28rpx;
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ .add-popup {
|
|
|
+ padding: 40rpx;
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 16rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .add-input {
|
|
|
+ width: 100%;
|
|
|
+ padding: 20rpx;
|
|
|
+ border: 1px solid #eee;
|
|
|
+ border-radius: 8rpx;
|
|
|
+ margin-bottom: 40rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .button-group {
|
|
|
+ display: flex;
|
|
|
+ gap: 20rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .confirm-button {
|
|
|
+ flex: 1;
|
|
|
+ background: #007aff;
|
|
|
+ color: #fff;
|
|
|
+ }
|
|
|
+
|
|
|
+ .cancel-button {
|
|
|
+ flex: 1;
|
|
|
+ background: #ff3b30;
|
|
|
+ color: #fff;
|
|
|
+ }
|
|
|
+</style>
|