预定义组件备份
This commit is contained in:
parent
d4a6a63b65
commit
a7f9544bc5
|
|
@ -0,0 +1,97 @@
|
||||||
|
<template>
|
||||||
|
<view class="form-checkbox">
|
||||||
|
<view v-for="(item, index) in options" :key="index" class="checkbox-item" @click="toggle(item)">
|
||||||
|
<view :class="['checkbox-dot', { checked: isSelected(item.value) }]">
|
||||||
|
<text v-if="isSelected(item.value)" class="check-icon">✓</text>
|
||||||
|
</view>
|
||||||
|
<text class="checkbox-label">{{ item.label }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'FormItemCheckbox',
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: Array,
|
||||||
|
default: function () {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
type: Array,
|
||||||
|
default: function () {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
selectedValues: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value: {
|
||||||
|
handler: function (val) {
|
||||||
|
this.selectedValues = Array.isArray(val) ? val.slice() : [];
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
isSelected: function (val) {
|
||||||
|
return this.selectedValues.indexOf(val) > -1;
|
||||||
|
},
|
||||||
|
toggle: function (item) {
|
||||||
|
var index = this.selectedValues.indexOf(item.value);
|
||||||
|
if (index > -1) {
|
||||||
|
this.selectedValues.splice(index, 1);
|
||||||
|
} else {
|
||||||
|
this.selectedValues.push(item.value);
|
||||||
|
}
|
||||||
|
this.$emit('input', this.selectedValues.slice());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.form-checkbox {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 16rpx 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-dot {
|
||||||
|
width: 36rpx;
|
||||||
|
height: 36rpx;
|
||||||
|
border-radius: 6rpx;
|
||||||
|
border: 2rpx solid #dddddd;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-right: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-dot.checked {
|
||||||
|
border-color: #e8101e;
|
||||||
|
background-color: #e8101e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.check-icon {
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-label {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,112 @@
|
||||||
|
<template>
|
||||||
|
<view class="form-image">
|
||||||
|
<view class="image-list">
|
||||||
|
<view v-for="(item, index) in imageList" :key="index" class="image-item">
|
||||||
|
<image :src="item" mode="aspectFill" class="preview-image" @click="previewImage(index)" />
|
||||||
|
<view class="delete-btn" @click.stop="deleteImage(index)">
|
||||||
|
<text class="delete-icon">×</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-if="imageList.length < maxCount" class="image-item add-btn" @click="chooseImage">
|
||||||
|
<text class="add-icon">+</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "FormItemImage",
|
||||||
|
props: {
|
||||||
|
value: { type: Array, default: function() { return []; } },
|
||||||
|
maxCount: { type: Number, default: 9 }
|
||||||
|
},
|
||||||
|
data: function() {
|
||||||
|
return {
|
||||||
|
imageList: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value: {
|
||||||
|
handler: function(val) {
|
||||||
|
this.imageList = Array.isArray(val) ? val.slice() : [];
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
chooseImage: function() {
|
||||||
|
var remaining = this.maxCount - this.imageList.length;
|
||||||
|
if (remaining <= 0) return;
|
||||||
|
var self = this;
|
||||||
|
uni.chooseImage({
|
||||||
|
count: remaining,
|
||||||
|
sizeType: ["compressed"],
|
||||||
|
sourceType: ["album", "camera"],
|
||||||
|
success: function(res) {
|
||||||
|
self.imageList = self.imageList.concat(res.tempFilePaths);
|
||||||
|
self.$emit("input", self.imageList);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
deleteImage: function(index) {
|
||||||
|
this.imageList.splice(index, 1);
|
||||||
|
this.$emit("input", this.imageList);
|
||||||
|
},
|
||||||
|
previewImage: function(index) {
|
||||||
|
uni.previewImage({
|
||||||
|
urls: this.imageList,
|
||||||
|
current: index
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.form-image {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.image-list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16rpx;
|
||||||
|
}
|
||||||
|
.image-item {
|
||||||
|
width: 200rpx;
|
||||||
|
height: 200rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.preview-image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.delete-btn {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
width: 40rpx;
|
||||||
|
height: 40rpx;
|
||||||
|
background-color: rgba(0, 0, 0, 0.6);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.delete-icon {
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 28rpx;
|
||||||
|
}
|
||||||
|
.add-btn {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border: 2rpx dashed #cccccc;
|
||||||
|
}
|
||||||
|
.add-icon {
|
||||||
|
font-size: 60rpx;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
<template>
|
||||||
|
<input type="number" class="form-input" :value="value" :placeholder="placeholder" placeholder-class="placeholder"
|
||||||
|
@input="$emit('input', $event.detail.value)" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'FormItemNumber',
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: '请输入数字'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.form-input {
|
||||||
|
flex: 1;
|
||||||
|
height: 80rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333333;
|
||||||
|
text-align: center;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
padding: 0 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder {
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
<template>
|
||||||
|
<view class="form-radio">
|
||||||
|
<view v-for="(item, index) in options" :key="index" class="radio-item" @click="onSelect(item.value)">
|
||||||
|
<view class="radio-dot" :class="{ active: value == item.value }"></view>
|
||||||
|
<text class="radio-label">{{ item.label }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "FormItemRadio",
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ""
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
type: Array,
|
||||||
|
default: function() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onSelect: function(val) {
|
||||||
|
this.$emit("input", val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.form-radio {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.radio-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 40rpx;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
}
|
||||||
|
.radio-dot {
|
||||||
|
width: 36rpx;
|
||||||
|
height: 36rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 2rpx solid #cccccc;
|
||||||
|
margin-right: 12rpx;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.radio-dot.active {
|
||||||
|
border-color: #e8101e;
|
||||||
|
background-color: #e8101e;
|
||||||
|
}
|
||||||
|
.radio-dot.active::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
width: 16rpx;
|
||||||
|
height: 16rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
.radio-label {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
<template>
|
||||||
|
<view class="form-richtext">
|
||||||
|
<view class="richtext-toolbar">
|
||||||
|
<text class="toolbar-btn" @click="insertTag('b')">加粗</text>
|
||||||
|
<text class="toolbar-btn" @click="insertTag('i')">斜体</text>
|
||||||
|
<text class="toolbar-btn" @click="insertImage">图片</text>
|
||||||
|
</view>
|
||||||
|
<textarea class="richtext-editor" :value="value" placeholder="请输入图文内容" placeholder-class="placeholder"
|
||||||
|
@input="$emit('input', $event.detail.value)" />
|
||||||
|
<view v-if="value" class="richtext-preview">
|
||||||
|
<rich-text :nodes="value" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "FormItemRichtext",
|
||||||
|
props: {
|
||||||
|
value: { type: String, default: "" },
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
insertTag(tag) {
|
||||||
|
const text = `<${tag}></${tag}>`;
|
||||||
|
this.$emit("input", (this.value || "") + text);
|
||||||
|
},
|
||||||
|
insertImage() {
|
||||||
|
uni.chooseImage({
|
||||||
|
count: 1,
|
||||||
|
success: (res) => {
|
||||||
|
const imgTag = `<img src="${res.tempFilePaths[0]}" />`;
|
||||||
|
this.$emit("input", (this.value || "") + imgTag);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.form-richtext {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.richtext-toolbar {
|
||||||
|
display: flex;
|
||||||
|
gap: 16rpx;
|
||||||
|
padding: 16rpx;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
border-radius: 8rpx 8rpx 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-btn {
|
||||||
|
padding: 8rpx 16rpx;
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-radius: 4rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.richtext-editor {
|
||||||
|
width: 100%;
|
||||||
|
height: 300rpx;
|
||||||
|
background-color: #ffffff;
|
||||||
|
border: 2rpx solid #e0e0e0;
|
||||||
|
border-top: none;
|
||||||
|
border-radius: 0 0 8rpx 8rpx;
|
||||||
|
padding: 20rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder {
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.richtext-preview {
|
||||||
|
margin-top: 16rpx;
|
||||||
|
padding: 16rpx;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
<template>
|
||||||
|
<picker :range="optionLabels" @change="onChange">
|
||||||
|
<view class="form-select">
|
||||||
|
<text :class="['select-text', selectedLabel ? '' : 'placeholder']">
|
||||||
|
{{ selectedLabel || placeholder }}
|
||||||
|
</text>
|
||||||
|
<image src="https://mrrplus.oss-cn-beijing.aliyuncs.com/wxstaic/images/arrow_right.png" class="arrow-right" mode="aspectFit" />
|
||||||
|
</view>
|
||||||
|
</picker>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "FormItemSelect",
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ""
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
type: Array,
|
||||||
|
default: function() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: "请选择"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
optionLabels: function() {
|
||||||
|
return this.options.map(function(item) {
|
||||||
|
return item.label;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
selectedLabel: function() {
|
||||||
|
var self = this;
|
||||||
|
var found = this.options.find(function(item) {
|
||||||
|
return item.value == self.value;
|
||||||
|
});
|
||||||
|
return found ? found.label : "";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onChange: function(e) {
|
||||||
|
var index = e.detail.value;
|
||||||
|
var selected = this.options[index];
|
||||||
|
if (selected) {
|
||||||
|
this.$emit("input", selected.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.form-select {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
height: 80rpx;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
padding: 0 24rpx;
|
||||||
|
}
|
||||||
|
.select-text {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
.placeholder {
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
.arrow-right {
|
||||||
|
width: 24rpx;
|
||||||
|
height: 24rpx;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
<template>
|
||||||
|
<input type="text" class="form-input" :value="value" :placeholder="placeholder" placeholder-class="placeholder"
|
||||||
|
@input="$emit('input', $event.detail.value)" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'FormItemText',
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: '请输入'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.form-input {
|
||||||
|
flex: 1;
|
||||||
|
height: 80rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333333;
|
||||||
|
text-align: center;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
padding: 0 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder {
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
<template>
|
||||||
|
<view class="textarea-wrap">
|
||||||
|
<textarea class="form-textarea" :value="value" :placeholder="placeholder" placeholder-class="placeholder"
|
||||||
|
maxlength="200" @input="$emit('input', $event.detail.value)" />
|
||||||
|
<text class="char-count">{{ (value || '').length }}/200</text>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'FormItemTextarea',
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: '请输入'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.textarea-wrap {
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-textarea {
|
||||||
|
width: 100%;
|
||||||
|
height: 150rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333333;
|
||||||
|
line-height: 1.5;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
padding: 20rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder {
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.char-count {
|
||||||
|
position: absolute;
|
||||||
|
right: 16rpx;
|
||||||
|
bottom: 16rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
<template>
|
||||||
|
<view class="form-video">
|
||||||
|
<view v-if="videoUrl" class="video-preview">
|
||||||
|
<video :src="videoUrl" class="video-player" controls />
|
||||||
|
<view class="delete-btn" @click="deleteVideo">
|
||||||
|
<text class="delete-icon">×</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-else class="video-add" @click="chooseVideo">
|
||||||
|
<text class="add-icon">+</text>
|
||||||
|
<text class="add-text">选择视频</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "FormItemVideo",
|
||||||
|
props: {
|
||||||
|
value: { type: String, default: "" }
|
||||||
|
},
|
||||||
|
data: function() {
|
||||||
|
return {
|
||||||
|
videoUrl: ""
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value: {
|
||||||
|
handler: function(val) {
|
||||||
|
this.videoUrl = val || "";
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
chooseVideo: function() {
|
||||||
|
var self = this;
|
||||||
|
uni.chooseVideo({
|
||||||
|
sourceType: ["album", "camera"],
|
||||||
|
maxDuration: 60,
|
||||||
|
success: function(res) {
|
||||||
|
self.videoUrl = res.tempFilePath;
|
||||||
|
self.$emit("input", self.videoUrl);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
deleteVideo: function() {
|
||||||
|
this.videoUrl = "";
|
||||||
|
this.$emit("input", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.form-video {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.video-preview {
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.video-player {
|
||||||
|
width: 100%;
|
||||||
|
height: 400rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
}
|
||||||
|
.delete-btn {
|
||||||
|
position: absolute;
|
||||||
|
top: 16rpx;
|
||||||
|
right: 16rpx;
|
||||||
|
width: 48rpx;
|
||||||
|
height: 48rpx;
|
||||||
|
background-color: rgba(0, 0, 0, 0.6);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.delete-icon {
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 32rpx;
|
||||||
|
}
|
||||||
|
.video-add {
|
||||||
|
width: 300rpx;
|
||||||
|
height: 300rpx;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border: 2rpx dashed #cccccc;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.add-icon {
|
||||||
|
font-size: 60rpx;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
.add-text {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #999999;
|
||||||
|
margin-top: 8rpx;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,197 @@
|
||||||
|
<template>
|
||||||
|
<view class="dynamic-form">
|
||||||
|
<view v-for="(field, index) in fields" :key="field.id || index" class="form-item"
|
||||||
|
:class="{ 'form-item-up': isUpType(field.type) }">
|
||||||
|
<view class="form-header">
|
||||||
|
<text class="form-label" :class="{ required: field.is_required == 1 }">{{ field.label }}</text>
|
||||||
|
<text v-if="field.tips" class="form-tips">{{ field.tips }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="form-control">
|
||||||
|
<!-- 单行文本 -->
|
||||||
|
<form-item-text v-if="field.type === 'text'" :value="formData[field.key]"
|
||||||
|
:placeholder="field.placeholder" @input="onInput(field.key, $event)" />
|
||||||
|
<!-- 多行文本 -->
|
||||||
|
<form-item-textarea v-else-if="field.type === 'textarea'" :value="formData[field.key]"
|
||||||
|
:placeholder="field.placeholder" @input="onInput(field.key, $event)" />
|
||||||
|
<!-- 数字输入 -->
|
||||||
|
<form-item-number v-else-if="field.type === 'number'" :value="formData[field.key]"
|
||||||
|
:placeholder="field.placeholder" @input="onInput(field.key, $event)" />
|
||||||
|
<!-- 多图上传 -->
|
||||||
|
<form-item-image v-else-if="field.type === 'image_multi'" :value="formData[field.key]"
|
||||||
|
:maxCount="field.maxCount || 9" @input="onInput(field.key, $event)" />
|
||||||
|
<!-- 视频上传 -->
|
||||||
|
<form-item-video v-else-if="field.type === 'video'" :value="formData[field.key]"
|
||||||
|
@input="onInput(field.key, $event)" />
|
||||||
|
<!-- 下拉选择 -->
|
||||||
|
<form-item-select v-else-if="field.type === 'select'" :value="formData[field.key]"
|
||||||
|
:options="field.options" :placeholder="field.placeholder" @input="onInput(field.key, $event)" />
|
||||||
|
<!-- 单选 -->
|
||||||
|
<form-item-radio v-else-if="field.type === 'single_select'" :value="formData[field.key]"
|
||||||
|
:options="field.options" @input="onInput(field.key, $event)" />
|
||||||
|
<!-- 多选 -->
|
||||||
|
<form-item-checkbox v-else-if="field.type === 'multi_select'" :value="formData[field.key]"
|
||||||
|
:options="field.options" @input="onInput(field.key, $event)" />
|
||||||
|
<!-- 图文编辑器 -->
|
||||||
|
<form-item-richtext v-else-if="field.type === 'richtext_editor'" :value="formData[field.key]"
|
||||||
|
@input="onInput(field.key, $event)" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import FormItemText from './FormItemText.vue';
|
||||||
|
import FormItemTextarea from './FormItemTextarea.vue';
|
||||||
|
import FormItemNumber from './FormItemNumber.vue';
|
||||||
|
import FormItemImage from './FormItemImage.vue';
|
||||||
|
import FormItemVideo from './FormItemVideo.vue';
|
||||||
|
import FormItemSelect from './FormItemSelect.vue';
|
||||||
|
import FormItemRadio from './FormItemRadio.vue';
|
||||||
|
import FormItemCheckbox from './FormItemCheckbox.vue';
|
||||||
|
import FormItemRichtext from './FormItemRichtext.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'DynamicForm',
|
||||||
|
components: {
|
||||||
|
FormItemText,
|
||||||
|
FormItemTextarea,
|
||||||
|
FormItemNumber,
|
||||||
|
FormItemImage,
|
||||||
|
FormItemVideo,
|
||||||
|
FormItemSelect,
|
||||||
|
FormItemRadio,
|
||||||
|
FormItemCheckbox,
|
||||||
|
FormItemRichtext
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
fields: {
|
||||||
|
type: Array,
|
||||||
|
default: function () {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: Object,
|
||||||
|
default: function () {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
formData: {}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value: {
|
||||||
|
handler: function (val) {
|
||||||
|
this.formData = Object.assign({}, val);
|
||||||
|
},
|
||||||
|
immediate: true,
|
||||||
|
deep: true
|
||||||
|
},
|
||||||
|
fields: {
|
||||||
|
handler: function (val) {
|
||||||
|
var self = this;
|
||||||
|
if (val && val.length > 0) {
|
||||||
|
val.forEach(function (field) {
|
||||||
|
if (self.formData[field.key] === undefined) {
|
||||||
|
self.$set(self.formData, field.key, self.getDefaultValue(field.type));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
isUpType: function (type) {
|
||||||
|
return type === 'image_multi' || type === 'video';
|
||||||
|
},
|
||||||
|
getDefaultValue: function (type) {
|
||||||
|
if (type === 'multi_select') {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
if (type === 'image_multi') {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
onInput: function (key, val) {
|
||||||
|
this.$set(this.formData, key, val);
|
||||||
|
this.$emit('input', Object.assign({}, this.formData));
|
||||||
|
},
|
||||||
|
validate: function () {
|
||||||
|
for (var i = 0; i < this.fields.length; i++) {
|
||||||
|
var field = this.fields[i];
|
||||||
|
if (field.is_required == 1) {
|
||||||
|
var val = this.formData[field.key];
|
||||||
|
if (val === undefined || val === null || val === '' || (Array.isArray(val) && val.length === 0)) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '请填写' + field.label,
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
getData: function () {
|
||||||
|
return Object.assign({}, this.formData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.dynamic-form {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 24rpx;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 10rpx;
|
||||||
|
margin-bottom: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item-up {
|
||||||
|
flex-flow: column nowrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-label {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-label.required::before {
|
||||||
|
content: '*';
|
||||||
|
color: #e8101e;
|
||||||
|
margin-right: 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-tips {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #999999;
|
||||||
|
margin-left: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control {
|
||||||
|
width: 100%;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -120,14 +120,14 @@ const request = async (options, isUpdate) => {
|
||||||
|
|
||||||
if (process.env.NODE_ENV === "development") {
|
if (process.env.NODE_ENV === "development") {
|
||||||
baseURL = url; // 发布到生产环境时,此处代码会被摇树移除掉。
|
baseURL = url; // 发布到生产环境时,此处代码会被摇树移除掉。
|
||||||
// baseURL = "http://116.63.163.121:93"; // 发布到生产环境时,此处代码会被摇树移除掉。
|
baseURL = "http://116.63.163.121:93"; // 发布到生产环境时,此处代码会被摇树移除掉。
|
||||||
//baseURL = 'http://60.247.146.5:96'; // 发布到生产环境时,此处代码会被摇树移除掉。
|
//baseURL = 'http://116.63.163.121:96'; // 发布到生产环境时,此处代码会被摇树移除掉。
|
||||||
baseURL = "https://app.mrrweb.com.cn";
|
// baseURL = "https://app.mrrweb.com.cn";
|
||||||
} else {
|
} else {
|
||||||
baseURL = url; // 发布到生产环境时,此处代码会被摇树移除掉。
|
baseURL = url; // 发布到生产环境时,此处代码会被摇树移除掉。
|
||||||
// baseURL = "http://116.63.163.121:93"; // 发布到生产环境时,此处代码会被摇树移除掉。
|
baseURL = "http://116.63.163.121:93"; // 发布到生产环境时,此处代码会被摇树移除掉。
|
||||||
//baseURL = 'http://60.247.146.5:96'; // 发布到生产环境时,此处代码会被摇树移除掉。
|
//baseURL = 'http://116.63.163.121:96'; // 发布到生产环境时,此处代码会被摇树移除掉。
|
||||||
baseURL = "https://app.mrrweb.com.cn";
|
// baseURL = "https://app.mrrweb.com.cn";
|
||||||
|
|
||||||
console.log("生产环境");
|
console.log("生产环境");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue