| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 | 
							- <template>
 
- 	<view class="phone-radio-group data-check-radio-group">
 
- 		<!-- 技能块展示 -->
 
- 		<view v-for="item in displayedList" :key="item.id" class="phone-radio-item"
 
- 			:class="{ radioActive: isSelected(item.id) }" @click="toggleSelect(item)">
 
- 			{{ item.name }}
 
- 		</view>
 
- 		<!-- 添加按钮 -->
 
- 		<view v-if="showAddButton" class="radio-add-btn" @click="handleAdd">
 
- 			+ 添加
 
- 		</view>
 
- 		<!-- 展开/收起按钮 -->
 
- 		<view class="radio-btn-box label-radio-btn-box">
 
- 			<view v-if="showExpandButton" :class="[{ 'radio-btn': true }, showAll ? 'collapsed-btn' : 'expanded-btn']"
 
- 				@click="toggleExpand">
 
- 				{{ showAll ? '收起' : `展开` }}
 
- 			</view>
 
- 		</view>
 
- 		<!-- 	<view v-if="showExpandButton" class="expand-button" @click="toggleExpand">
 
- 			{{ showAll ? '收起' : `展开剩余${remainingCount}项` }}
 
- 		</view> -->
 
- 		<!-- 添加弹窗 -->
 
- 		<uni-popup ref="addPopup" type="dialog" :animation="false" :is-mask-click="false">
 
- 			<view class="phone-common-dialog">
 
- 				<view class="common-body-box">
 
- 					<view class="common-title">新增技能</view>
 
- 					<view class="common-input-box">
 
- 						<input v-model="newName" placeholder="请输入技能名称" class="common-input-margin" />
 
- 					</view>
 
- 				</view>
 
- 				<view class="common-btn-box">
 
- 					<view class="not-confirm-btn" @click="cancelAdd">取消</view>
 
- 					<view class="confirm-btn" @click="confirmAdd">确认</view>
 
- 				</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)
 
- 			},
 
- 			// 外部传入的已选id(单选时为单个id,多选时为id数组)
 
- 			selectedIds: {
 
- 				type: [Array, Number,String],
 
- 				default: () => []
 
- 			},
 
- 			selectedNames: {
 
- 				type: String,
 
- 				default: ''
 
- 			}
 
- 		},
 
- 		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;
 
- 			}
 
- 		},
 
- 		watch: {
 
- 			// 监听外部传入的selectedIds变化,更新selectedData
 
- 			selectedIds: {
 
- 				handler(newVal) {
 
- 					if (this.mode === 'single') {
 
- 						// 单选模式
 
- 						const selectedItem = this.list.find(item => item.id == newVal);
 
- 						this.selectedData = selectedItem ? [selectedItem] : [];
 
- 					} else {
 
- 						// 多选模式
 
- 						this.selectedData = this.list.filter(item => newVal.includes(item.id));
 
- 					}
 
- 				}
 
- 			},
 
- 			// 监听外部传入的selectedNames变化,更新selectedData
 
- 			selectedNames: {
 
- 				immediate: true,
 
- 				handler(newVal) {
 
- 					if (!newVal) {
 
- 						this.selectedData = [];
 
- 						return;
 
- 					}
 
- 					// 将字符串解析为名称数组
 
- 					const names = newVal.split(',').map(name => name.trim());
 
- 					// 根据名称从list中找到对应的数据
 
- 					this.selectedData = this.list.filter(item => names.includes(item.name));
 
- 				}
 
- 			}
 
- 		},
 
- 		methods: {
 
- 			isSelected(id) {
 
- 				return this.selectedData.some(item => item.id === id);
 
- 			},
 
- 			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,
 
- 					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>
 
- 	.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>
 
 
  |