商品添加封装成组件

v1.0.0
于肖磊 2024-08-21 16:28:19 +08:00
parent 151a7799df
commit 9f0b2e28bf
8 changed files with 149 additions and 54 deletions

View File

@ -4,7 +4,8 @@
<li v-for="(item, index) in from" :key="item.id" :class="className" class="flex gap-y-16 re" @click="on_click(item, index)">
<el-icon class="iconfont icon-drag size-16 cursor-move" />
<slot :row="item" :index="index" />
<el-icon v-if="type == 'line'" class="iconfont icon-del-o size-16" @click="remove(index)" />
<el-icon v-if="isShowEdit" class="iconfont icon-commodity-edit size-16 cr-primary do-not-trigger two-click" @click="edit(index)" />
<el-icon v-if="type == 'line'" class="iconfont icon-del-o size-16 do-not-trigger" @click="remove(index)" />
<el-icon v-if="type == 'card'" class="iconfont icon-close-o size-16 abs cr-c top-de-5 right-de-5" @click="remove(index)" />
</li>
</TransitionGroup>
@ -13,16 +14,18 @@
<script setup lang="ts">
import { VueDraggable } from 'vue-draggable-plus';
const emits = defineEmits(['click', 'remove', 'onSort']);
const emits = defineEmits(['click', 'remove', 'edit', 'onSort']);
interface Props {
data: any; //
type?: string; // card: line:
spaceCol?: number; //
iconPosition?: string; // top/bottom/center
isShowEdit?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
type: () => 'line',
isShowEdit: false,
spaceCol: () => 5,
iconPosition: 'center',
});
@ -42,7 +45,6 @@ if (props.type == 'card') {
}
const from = ref(props.data);
const on_click = (item: any, index: number) => {
emits('click', item, index);
};
@ -50,6 +52,9 @@ const on_click = (item: any, index: number) => {
const remove = (index: number) => {
emits('remove', index);
};
const edit = (index: number) => {
emits('edit', index);
};
//
const on_sort = () => {
emits('onSort', from);
@ -64,7 +69,7 @@ const on_sort = () => {
.size-16 {
font-size: 1.6rem !important;
}
.icon-del-o {
.icon-del-o, .icon-commodity-edit {
cursor: pointer;
}
.cursor-move {

View File

@ -0,0 +1,76 @@
<template>
<drag :data="drag_list" :space-col="20" :is-show-edit="true" @remove="remove" @on-sort="on_sort" @edit="edit">
<template #default="{ row, index }">
<upload v-model="row.new_url" :limit="1" size="40" styles="2"></upload>
<el-image :src="row.link[imgParams]" fit="contain" class="img">
<template #error>
<div class="bg-f5 flex-row jc-c align-c radius h w">
<icon name="error-img" size="16" color="9"></icon>
</div>
</template>
</el-image>
<template v-if="index === edit_index">
<el-input v-model="row.new_title" placeholder="请输入链接" type="textarea" class="flex-1 do-not-trigger" :rows="2"></el-input>
</template>
<template v-else>
<div class="flex-1 flex-width text-line-2 size-12 self-s">{{ row.new_title }}</div>
</template>
</template>
</drag>
</template>
<script lang="ts" setup>
interface Props {
list: any[];
imgParams: string;
}
const props = withDefaults(defineProps<Props>(), {
imgParams: 'cover',
isouterClick: false,
});
const drag_list = ref(props.list);
watchEffect(() => {
drag_list.value = props.list;
});
onMounted(() => {
//
document.addEventListener('click', outerClick);
});
onUnmounted(() => {
//
document.removeEventListener('click', outerClick);
});
const edit_index = ref(-1);
//
const outerClick = (e: any) => {
if (!e.target.className.includes('do-not-trigger') && !e.target.parentNode.className.includes('do-not-trigger')) {
edit_index.value = -1;
}
};
const emits = defineEmits(['remove', 'onsort']);
const remove = (index: number) => {
if (edit_index.value === index) {
edit_index.value = -1;
}
emits('remove', index);
}
const on_sort = (item: any) => {
emits('onsort', item);
}
const edit = (index: number) => {
if (edit_index.value === index) {
edit_index.value = -1;
} else {
edit_index.value = index;
}
}
</script>
<style lang="scss" scoped>
.img {
width: 4rem;
height: 4rem;
}
</style>

View File

@ -14,27 +14,35 @@
</el-menu>
</div>
<div class="right-content flex-1">
<!-- 商城链接/插件 -->
<template v-if="link_select == 'shop' || link_select == 'plugins'">
<link-list :key="link_select" v-model="link_value" :type="link_select" :reset="reset_compontent"></link-list>
</template>
<!-- 商品分类 -->
<template v-else-if="link_select == 'goods-category'">
<link-goods-category v-model="link_value" :reset="reset_compontent"></link-goods-category>
</template>
<!-- 商品搜索 -->
<template v-else-if="link_select == 'goods-search'">
<link-goods-search :reset="reset_compontent" :status="component_status" @update:link="goods_category_link" @type="goods_category_type_change"></link-goods-search>
</template>
<!-- 商品页面 -->
<template v-else-if="link_select == 'goods'">
<link-goods v-model="link_value" :multiple="multiple" :reset="reset_compontent"></link-goods>
</template>
<!-- 文章页面 -->
<template v-else-if="link_select == 'article'">
<link-articles v-model="link_value" :multiple="multiple" :reset="reset_compontent"></link-articles>
</template>
<!-- diy页面/页面设计/自定义页面 -->
<template v-else-if="link_select == 'diy' || link_select == 'design' || link_select == 'custom-view'">
<link-table :key="link_select" v-model="link_value" :multiple="multiple" :type="link_select" :reset="reset_compontent"></link-table>
</template>
<!-- 品牌 -->
<template v-else-if="link_select == 'brand'">
<link-brand v-model="link_value" :multiple="multiple" :reset="reset_compontent"></link-brand>
</template>
<!-- 自定义链接 -->
<template v-else-if="link_select == 'custom-url'">
<link-custom :reset="reset_compontent" :status="component_status" @update:link="custom_link"></link-custom>
</template>

View File

@ -10,8 +10,8 @@
</template>
<template v-else>
<template v-if="!isEmpty(item)">
<template v-if="!isEmpty(item.new_src)">
<image-empty v-model="item.new_src[0]" :class="`flex-img${product_style} flex align-c jc-c`" :style="content_img_radius"></image-empty>
<template v-if="!isEmpty(item.new_url)">
<image-empty v-model="item.new_url[0]" :class="`flex-img${product_style} flex align-c jc-c`" :style="content_img_radius"></image-empty>
</template>
<template v-else-if="!isEmpty(item.images)">
<el-image :src="item.images" :class="`flex-img${product_style} flex align-c jc-c`" fit="contain" class="img"></el-image>
@ -85,7 +85,7 @@
</template>
<script setup lang="ts">
import { common_styles_computer, gradient_handle, padding_computer, radius_computer } from '@/utils';
import { isEmpty } from 'lodash';
import { isEmpty, cloneDeep } from 'lodash';
import ShopAPI from '@/api/shop';
const props = defineProps({
@ -112,7 +112,7 @@ const { form, new_style } = toRefs(state);
interface product_list {
title: string;
images: string;
new_src: string[];
new_url: string[];
min_original_price: string;
show_original_price_symbol: string;
show_original_price_unit: string;
@ -130,7 +130,7 @@ const default_list = {
show_price_unit: "",
sales_count: "1000",
images: '',
new_src: []
new_url: []
}
const list = ref<product_list[]>([]);
const get_products = () => {
@ -155,7 +155,11 @@ const get_products = () => {
watchEffect(() => {
if (form.value.product_check == '0') {
if (!isEmpty(form.value.product_list)) {
list.value = form.value.product_list;
list.value = cloneDeep(form.value.product_list).map((item: any) => ({
...item.link,
title: item.new_title,
new_url: item.new_url,
}));
} else {
list.value = Array(4).fill(default_list);
}
@ -356,6 +360,7 @@ const style_container = computed(() => {
}
.flex-img0 {
height: auto;
max-height: 12rem;
width: 11rem;
}
.flex-img1 {

View File

@ -10,7 +10,7 @@
</el-form-item>
</card-container>
<div class="content-height bg-f">
<card-container class="card-container-br">
<card-container class="card-container-br" @click="card_click">
<div class="mb-12">商品设置</div>
<el-form-item label="添加商品">
<el-radio-group v-model="form.product_check">
@ -19,21 +19,7 @@
</el-form-item>
<template v-if="form.product_check === '0'">
<div class="nav-list">
<drag :data="form.product_list" :space-col="20" @remove="product_list_remove" @on-sort="product_list_sort">
<template #default="{ row }">
<upload v-model="row.new_src" :limit="1" size="40" styles="2"></upload>
<el-image :src="row.url" fit="contain" class="img">
<template #error>
<div class="bg-f5 flex-row jc-c align-c radius h w">
<icon name="error-img" size="16" color="9"></icon>
</div>
</template>
</el-image>
<div class="flex-1 flex-width">
<url-value v-model="row.href"></url-value>
</div>
</template>
</drag>
<dragGroup :list="form.product_list" img-params="images" @onsort="product_list_sort" @remove="product_list_remove"></dragGroup>
<el-button class="mt-20 w" @click="add">+</el-button>
</div>
</template>
@ -67,6 +53,7 @@
<product-show-config :value="form"></product-show-config>
</div>
</el-form>
<url-value-dialog v-model:dialog-visible="url_value_dialog_visible" :type="['goods']" multiple @update:model-value="url_value_dialog_call_back"></url-value-dialog>
</div>
</template>
<script setup lang="ts">
@ -138,27 +125,38 @@ onBeforeMount(() => {
init();
});
const product_list_remove = (index: number) => {
form.value.product_list.splice(index, 1);
};
const add = () => {
form.value.product_list.push({
id: get_math(),
src: 'carousel',
new_src: [],
href: {},
});
url_value_dialog_visible.value = true;
};
//
const product_list_sort = (new_list: any) => {
form.value.product_list = new_list;
};
//
const product_list_remove = (index: number) => {
form.value.product_list.splice(index, 1);
};
const change_style = (val: any): void => {
form.value.product_style = val;
if (['3', '4', '5'].includes(val) && ['0', '1'].includes(form.value.shop_type)) {
form.value.shop_type = '2';
}
};
//
const url_value_dialog_visible = ref(false);
//
const url_value_dialog_call_back = (item: any[]) => {
item.forEach((item: any) => {
form.value.product_list.push({
id: get_math(),
new_url: [],
is_edit: false,
new_title: item.title,
link: item,
});
});
};
</script>
<style lang="scss" scoped>
.content {

View File

@ -3,24 +3,6 @@
<el-form :model="form" label-width="70">
<card-container class="mb-8">
<div class="mb-12">商品样式</div>
<el-form-item label="内容圆角">
<radius :value="form.shop_radius" @update:value="shop_radius_change"></radius>
</el-form-item>
<el-form-item label="图片圆角">
<radius :value="form.shop_img_radius" @update:value="img_radius_change"></radius>
</el-form-item>
<el-form-item label="内间距">
<padding :value="form.shop_padding" @update:value="shop_padding_change"></padding>
</el-form-item>
<el-form-item v-if="['0', '4'].includes(product_style)" label="内容间距">
<slider v-model="form.content_spacing" :max="100"></slider>
</el-form-item>
<el-form-item label="商品间距">
<slider v-model="form.content_outer_spacing" :max="100"></slider>
</el-form-item>
<el-form-item v-if="product_style == '5'" label="内容宽度">
<slider v-model="form.content_outer_width" :max="1000"></slider>
</el-form-item>
<el-form-item label="商品名称">
<text-size-type v-model:typeface="form.shop_title_typeface" v-model:size="form.shop_title_size"></text-size-type>
</el-form-item>
@ -45,6 +27,24 @@
<el-form-item label="评分颜色">
<color-picker v-model="form.shop_score_color" default-color="#000000"></color-picker>
</el-form-item>
<el-form-item label="内容圆角">
<radius :value="form.shop_radius" @update:value="shop_radius_change"></radius>
</el-form-item>
<el-form-item label="图片圆角">
<radius :value="form.shop_img_radius" @update:value="img_radius_change"></radius>
</el-form-item>
<el-form-item label="内间距">
<padding :value="form.shop_padding" @update:value="shop_padding_change"></padding>
</el-form-item>
<el-form-item v-if="['0', '4'].includes(product_style)" label="内容间距">
<slider v-model="form.content_spacing" :max="100"></slider>
</el-form-item>
<el-form-item label="商品间距">
<slider v-model="form.content_outer_spacing" :max="100"></slider>
</el-form-item>
<el-form-item v-if="product_style == '5'" label="内容宽度">
<slider v-model="form.content_outer_width" :max="1000"></slider>
</el-form-item>
</card-container>
<card-container class="mb-8">
<div class="mb-12">购物车按钮</div>

View File

@ -5,7 +5,7 @@ interface DefaultProductList {
product_check: string;
goods_category_ids: string[];
goods_brand_ids: string[];
product_list: [];
product_list: string[];
is_price_solo: boolean;
number: number;
sort: string;

View File

@ -311,5 +311,8 @@ $line: 5;
-webkit-line-clamp: #{$i};
line-clamp: #{$i}; //
-webkit-box-orient: vertical;
word-break: break-word;
overflow-wrap: break-word;
word-wrap: break-word;
}
}