自定义获取数据改版

v1.1.0
于肖磊 2024-11-28 14:38:42 +08:00
parent 2d234639cd
commit 543099e796
10 changed files with 558 additions and 201 deletions

View File

@ -1,19 +1,22 @@
<template>
<drag :data="drag_list" :space-col="20" :is-show-edit="true" @remove="remove" @on-sort="on_sort" @edit="edit" @replace="replace">
<template #default="{ row, index }">
<upload v-model="row.new_cover" :limit="1" size="40" styles="2"></upload>
<el-image :src="row.data[imgParams]" fit="contain" class="img radius-xs">
<template #error>
<div class="bg-f5 flex-row jc-c align-c radius-xs h w">
<icon name="error-img" size="16" color="9"></icon>
</div>
</template>
</el-image>
<!-- 自定义模式并且没有传递图片参数就不显示图片否则的话显示图片 -->
<template v-if="(type == 'custom' && !isEmpty(imgParams)) || type == 'other'">
<upload v-model="row.new_cover" :limit="1" size="40" styles="2"></upload>
<el-image :src="row.data[imgParams]" fit="contain" class="img radius-xs">
<template #error>
<div class="bg-f5 flex-row jc-c align-c radius-xs h w">
<icon name="error-img" size="16" color="9"></icon>
</div>
</template>
</el-image>
</template>
<template v-if="index === edit_index">
<el-input v-model="row.new_title" placeholder="请输入链接" type="textarea" class="flex-1 do-not-trigger" clearable :rows="2"></el-input>
</template>
<template v-else>
<div class="flex-1 flex-width text-line-2 size-12 self-s do-not-trigger" @dblclick="double_click(index)">{{ !isEmpty(row.new_title) ? row.new_title : row.data.title }}</div>
<div class="flex-1 flex-width text-line-2 size-12 self-s do-not-trigger" @dblclick="double_click(index)">{{ !isEmpty(row.new_title) ? row.new_title : row.data[props.titleParams] }}</div>
</template>
</template>
</drag>
@ -25,10 +28,14 @@ import { isEmpty } from 'lodash';
interface Props {
list: any[];
imgParams: string;
titleParams?: string;
type?: string;
}
const props = withDefaults(defineProps<Props>(), {
imgParams: 'cover',
titleParams: 'title',
type: 'other'
});
const drag_list = ref(props.list);
@ -81,13 +88,13 @@ const double_click = (index: number) => {
const edit_processing = (index: number) => {
const list = drag_list.value[index];
if (!isEmpty(list) && isEmpty(list.new_title)) {
list.new_title = list.data.title;
list.new_title = list.data[props.titleParams];
}
};
//
const edit_close_processing = (index: number) => {
const list = drag_list.value[index];
if (!isEmpty(list) && !isEmpty(list.new_title) && list.new_title === list.data.title) {
if (!isEmpty(list) && !isEmpty(list.new_title) && list.new_title === list.data[props.titleParams]) {
list.new_title = '';
}
};

View File

@ -0,0 +1,142 @@
<template>
<div :class="props.direction == 'vertical' ? 'flex-col gap-x-18' : 'flex-row gap-y-20 jc-e'">
<div v-for="(item, index) in props.filterData" :key="index" class="filter-style flex-row gap-12">
<div v-if="!isEmpty(item.title) && Number(props.titleWidth) > 0" class="title text-line-1" :style="`width: ${ props.titleWidth }px;`">{{ item.title }}</div>
<div class="w h filter-right">
<template v-if="item.type == 'select'">
<template v-if="item.config.data_level > 1">
<div class="flex-row gap-10">
<el-cascader v-model="new_data_Interface[item.form_name]" :placeholder="placeholder_config(item, 'select')" clearable class="w h" collapse-tags popper-class="filter-form-cascader" placement="left" :props="{ 'expandTrigger': 'hover', 'multiple': item.config.is_multiple == '1', 'checkStrictly': true, 'emitPath': false, 'value': item.data_key, 'label': item.data_name, 'children': item.config.children }" :options="selectData(item.data, item.const_key)" />
<template v-if="item.config.is_multiple == '1'">
<el-tooltip effect="dark" :show-after="200" :hide-after="200" content="父级选中包含所有子级" raw-content placement="top">
<icon name="miaosha-hdgz" size="12" color="#999"></icon>
</el-tooltip>
</template>
</div>
</template>
<template v-else>
<el-select v-model="new_data_Interface[item.form_name]" :multiple="item.config.is_multiple == '1'" collapse-tags :placeholder="placeholder_config(item, 'select')" clearable>
<el-option v-for="item1 in selectData(item.data, item.const_key)" :key="item1[item.data_key]" :label="item1[item.data_name]" :value="item1[item.data_key]" />
</el-select>
</template>
</template>
<template v-else-if="item.type == 'input'">
<template v-if="item.config.type == 'number'">
<el-input-number v-model="new_data_Interface[item.form_name]" :min="item.config?.min || 0" :max="item.config?.max || undefined" type="number" :placeholder="placeholder_config(item, 'input')" value-on-clear="min" class="w number-show" controls-position="right"></el-input-number>
</template>
<template v-else>
<el-input v-model="new_data_Interface[item.form_name]" :placeholder="placeholder_config(item, 'input')" clearable />
</template>
</template>
<template v-else-if="item.type == 'switch'">
<el-switch v-model="new_data_Interface[item.form_name]" active-value="1" inactive-value="0" />
</template>
<template v-else-if="item.type =='radio'">
<el-radio-group v-model="new_data_Interface[item.form_name]">
<el-radio v-for="item1 in selectData(item.data, item.const_key)" :key="item1[item.data_key]" :value="item1[item.data_key]">{{ item1[item.data_name] }}</el-radio>
</el-radio-group>
</template>
<template v-else-if="item.type =='checkbox'">
<el-checkbox-group v-model="new_data_Interface[item.form_name]">
<el-checkbox v-for="item1 in selectData(item.data, item.const_key)" :key="item1[item.data_key]" :value="item1[item.data_key]">{{ item1[item.data_name] }}</el-checkbox>
</el-checkbox-group>
</template>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { isEmpty } from 'lodash';
import { commonStore } from '@/store';
const common_store = commonStore();
interface filter {
const_key: string; // key
type: string; //
config: any;
title: string;
form_name: string;
data: any[];
data_key: string;
data_name: string;
}
const props = defineProps({
filterData: {
type: Array as PropType<filter[]>,
default: () => ([]),
},
direction: {
type: String,
default: 'vertical',
},
dataInterface: {
type: Object as PropType<any>,
default: () => {},
},
titleWidth: {
type: Number,
default: 0,
}
});
const new_data_Interface = ref<any>({})
//
watch(() => props.dataInterface, (new_val, old_val) => {
if (JSON.stringify(new_val)!= JSON.stringify(old_val)) {
new_data_Interface.value = { ...new_val }
}
}, { deep: true, immediate: true });
//
const emit = defineEmits(['form-change']);
watch(() => new_data_Interface.value, (val) => {
emit('form-change', val);
}, { deep: true });
const placeholder_config = computed(() => {
return (data: any, type: string) => {
if (!data.config.placeholder) {
return type == 'select'? `请选择${ data?.title || '' }` : `请输入${ data?.title || '' }`;
} else {
return data.config.placeholder;
}
}
});
//
const selectData = computed(() => {
return (data: any, type: string) => {
if (!isEmpty(data)) {
return data;
} else {
return !isEmpty((common_store.common as any)[type]) ? (common_store.common as any)[type] : [];
}
}
});
</script>
<style lang="scss" scoped>
.filter-style {
min-height: 3.2rem;
}
.filter-right {
min-width: 20rem;
}
.title {
font-size: 1.2rem;
line-height: 3.2rem;
text-align: right;
width: 100%;
color: #606266;
}
.number-show {
:deep(.el-input__wrapper .el-input__inner) {
text-align: left;
}
}
.custom-content {
padding: 10px;
border-bottom: 1px solid #ebeef5;
text-align: center;
}
</style>

View File

@ -0,0 +1,81 @@
<template>
<el-table :data="tableData" class="custom-table" style="width: 100%" height="438" :header-cell-style="{ background: '#f7f7f7' }" @row-click="row_click" @select="handle_select" @select-all="handle_select" >
<el-table-column v-if="multiple" type="selection" width="60" />
<el-table-column v-else label="#" width="60" type="">
<template #default="scope">
<el-radio v-model="template_selection" :label="scope.$index + ''">&nbsp;</el-radio>
</template>
</el-table-column>
<template v-for="(item, index) in tableColumnList" :key="index">
<el-table-column :prop="item.field" :label="item.name" :width="item?.width || ''">
<template #default="scope">
<template v-if="item.type == 'images'">
<image-empty v-if="scope.row[item.field]" v-model="scope.row[item.field]" fit="contain" class="img"></image-empty>
</template>
<template v-else-if="item.type == 'text'">
{{ scope.row[item.field] }}
</template>
</template>
</el-table-column>
</template>
<template #empty>
<no-data></no-data>
</template>
</el-table>
</template>
<script lang="ts" setup>
interface TableColumn {
field: string;
name: string;
width?: string;
type: string;
}
const props = defineProps({
tableData: {
type: Array,
default: () => ([]),
},
type: {
type: String,
default: 'id',
},
// tabs
tableColumnList: {
type: Array as PropType<TableColumn[]>,
default: () => ([]),
},
multiple: {
type: Boolean,
default: false,
}
});
const template_selection = ref('');
const emit = defineEmits(['select']);
//#region
//
const row_click = (row: any) => {
if (!props.multiple) {
//
const new_table_data = JSON.parse(JSON.stringify(props.tableData));
//
template_selection.value = new_table_data.findIndex((item: any) => item[props.type] == row[props.type]).toString();
emit('select', row);
}
};
//
const handle_select = (selection: any) => {
emit('select', selection);
};
//#endregion
</script>
<style lang="scss" scoped>
.custom-table {
.img {
width: 3.2rem;
}
}
</style>

View File

@ -0,0 +1,143 @@
<template>
<el-dialog v-model="dialogVisible" class="radius-lg" width="1168" draggable append-to-body :close-on-click-modal="false" :top="dialogPositionTop ? dialogPositionTop + 'px' : ''" @close="close_event">
<template #header>
<div class="title center re">
<div class="tc size-16 fw">{{ config?.popup_title || '' }}</div>
</div>
</template>
<div class="flex-col gap-20 w h pa-20">
<filter-form :filter-data="config.filter_form_config" direction="horizontal" :data-interface="default_data" @form-change="filter_form_change"></filter-form>
<table-config v-loading="loading" :table-data="tableData" :multiple="multiple" :table-column-list="config.header" @select="table_select"></table-config>
<div class="flex-row jc-e">
<el-pagination :current-page="pagination_data.page" background :page-size="pagination_data.page_size" :pager-count="5" layout="prev, pager, next" :total="pagination_data.data_total" @current-change="get_list" />
</div>
</div>
<template #footer>
<span class="dialog-footer">
<el-button class="plr-28 ptb-10" @click="close_event"></el-button>
<el-button class="plr-28 ptb-10" type="primary" @click="confirm_event"></el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import request from '@/utils/request';
import { isEmpty } from 'lodash';
const props = defineProps({
type: {
type: Array as PropType<string[]>,
default: () => [],
},
config: {
type: Object as PropType<any>,
default: () => {},
},
multiple: {
type: Boolean,
default: false,
},
dialogPositionTop: {
type: Number,
default: 0,
},
});
const dialogVisible = defineModel('dialogVisible', { type: Boolean, default: false });
//#region
const select_data = ref([]);
const table_select = (val: any) => {
select_data.value = val;
};
const emit = defineEmits(['confirm_event']);
const close_event = () => {
dialogVisible.value = false;
};
const confirm_event = () => {
dialogVisible.value = false;
emit('confirm_event', select_data.value);
};
//#endregion
//#region
//
const default_data = ref({});
const pagination_data = ref({
page: 1,
page_size: 10,
data_total: 0,
});
//
watchEffect(() => {
if (!isEmpty(props.config) && dialogVisible.value) {
//
const staging_data : any = {};
pagination_data.value = {
page: 1,
page_size: props.config?.page_size || 10,
data_total: 0,
}
//
// ,
props.config.filter_form_config.forEach((item: any) => {
let value : number | string | Array<any> = '';
if (item.type == 'checkbox' || item.type == 'select' && item.config.is_multiple == '1') { //
value = item.config.default ? item.config.default : [];
} else if (item.type == 'input' && item.config.type == 'number') { //
value = item.config.default ? item.config.default : 0;
} else if (item.type == 'switch') {
value = item.config.default ? item.config.default : "0";
}
staging_data[item.form_name] = value;
})
//
default_data.value = staging_data;
}
});
//
const filter_form_change = (val: any) => {
default_data.value = val;
//
pagination_data.value.page = 1;
};
//#endregion
//region
const get_list = (new_page: number) => {
pagination_data.value.page = new_page;
get_table_list(default_data.value);
}
const tableData = ref([]);
const loading = ref(false);
const get_table_list = (val: any) => {
tableData.value = [];
//
if (!isEmpty(val) && !isEmpty(props.config) && !isEmpty(props.config.data_url)) {
//
const data = {
...val,
page: pagination_data.value.page,
page_size: pagination_data.value.page_size,
}
loading.value = true;
request({
url: props.config.data_url, //
method: 'post', //
data //
}).then((res) => {
if (res.data) {
tableData.value = res.data.data_list;
pagination_data.value.data_total = res.data.data_total;
}
}).finally(() => {
loading.value = false;
});
}
}
watch(() => default_data.value, (val) => {
get_table_list(val);
}, { deep: true })
//#endregion
</script>
<style lang="scss" scoped>
</style>

View File

@ -1,15 +1,15 @@
<template>
<div :style="style_container">
<div class="w h re" :style="style_img_container">
<template v-if="data_source_content_list.length > 0 && form.data_source_direction == '0'">
<template v-if="data_source_content_list.length > 0 && form.data_source_direction == 'vertical'">
<div v-for="(item1, index1) in data_source_content_list" :key="index1" :style="style_chunk_container">
<div class="w h" :style="style_chunk_img_container">
<data-rendering :custom-list="form.custom_list" :source-list="item1" :source-type="form?.data_source || ''" :data-height="form.height" :scale="scale"></data-rendering>
</div>
</div>
</template>
<div v-else-if="data_source_content_list.length > 0 && ['1', '2'].includes(form.data_source_direction)" class="oh" :style="form.data_source_direction == '2' ? `height:100%;` : `height: ${ swiper_height }px;`">
<swiper :key="carouselKey" class="w flex" :direction="form.data_source_direction == '2' ? 'horizontal': 'vertical'" :height="swiper_height" :loop="true" :autoplay="autoplay" :slides-per-view="slides_per_view" :slides-per-group="slides_per_group" :allow-touch-move="false" :pause-on-mouse-enter="true" :modules="modules" @slide-change="slideChange">
<div v-else-if="data_source_content_list.length > 0 && ['vertical-scroll', 'horizontal'].includes(form.data_source_direction)" class="oh" :style="form.data_source_direction == 'horizontal' ? `height:100%;` : `height: ${ swiper_height }px;`">
<swiper :key="carouselKey" class="w flex" :direction="form.data_source_direction == 'horizontal' ? 'horizontal': 'vertical'" :height="swiper_height" :loop="true" :autoplay="autoplay" :slides-per-view="slides_per_view" :slides-per-group="slides_per_group" :allow-touch-move="false" :pause-on-mouse-enter="true" :modules="modules" @slide-change="slideChange">
<swiper-slide v-for="(item1, index1) in data_source_content_list" :key="index1">
<div :style="style_chunk_container">
<div class="w h" :style="style_chunk_img_container">
@ -106,8 +106,9 @@ const style_chunk_img_container = computed(() => common_img_computer(new_style.v
//
let data_source_content_list = computed(() => {
if (['goods', 'article', 'brand'].includes(form.value.data_source)) {
if (form.value.data_source_content.data_type == '0') {
//
if (form.value.is_custom_data == '1') {
if (form.value.data_source_content.data_type == 'appoint') {
return form.value.data_source_content?.data_list || [];
} else {
return !isEmpty(form.value.data_source_content) ?
@ -150,7 +151,7 @@ watchEffect(() => {
}
const { padding_top, padding_bottom, margin_bottom, margin_top } = new_style.value.data_style;
//
if (form.value.data_source_direction == '2') {
if (form.value.data_source_direction == 'horizontal') {
swiper_height.value = form.value.height * scale.value + padding_top + padding_bottom + margin_bottom + margin_top;
} else {
swiper_height.value = (form.value.height * scale.value + padding_top + padding_bottom + margin_bottom + margin_top) * form.value.data_source_carousel_col;

View File

@ -10,40 +10,43 @@
</el-form-item>
</card-container>
<!-- 筛选数据 -->
<template v-if="['goods', 'article', 'brand'].includes(form.data_source)">
<template v-if="!isEmpty(default_type_data)">
<div class="divider-line"></div>
<card-container>
<div class="mb-12">显示设置</div>
<el-form-item label="铺满方式">
<el-radio-group v-model="form.data_source_direction">
<el-radio value="0">纵向展示</el-radio>
<el-radio value="1">纵向滑动</el-radio>
<el-radio value="2">横向滑动</el-radio>
<el-radio v-for="(item, index) in default_type_data.show_type" :key="index" :value="item">{{ item == 'vertical' ? '' : item == 'vertical-scroll' ? '' : '' }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="['1', '2'].includes(form.data_source_direction)" label="每屏显示">
<el-form-item v-if="['vertical-scroll', 'horizontal'].includes(form.data_source_direction)" label="每屏显示">
<el-radio-group v-model="form.data_source_carousel_col">
<template v-if="form.data_source_direction == '2'">
<el-radio :value="1">单列展示</el-radio>
<el-radio :value="2">两列展示</el-radio>
<el-radio :value="3">三列展示</el-radio>
<el-radio :value="4">四列展示</el-radio>
<el-radio v-for="(item, index) in default_type_data.show_number" :key="index" :value="item">{{ item }}{{ form.data_source_direction == 'vertical-scroll' ? '' : '' }}</el-radio>
</el-radio-group>
</el-form-item>
</card-container>
<template v-if="!isEmpty(default_type_data.data_type)">
<div class="divider-line"></div>
<card-container>
<div class="mb-12">数据设置</div>
<div class="flex-col">
<el-form-item label="读取方式">
<el-radio-group v-model="form.data_source_content.data_type">
<el-radio v-for="(item, index) in default_type_data.data_type" :key="index" :value="item">{{ item == 'appoint' ? '' : '' }}</el-radio>
</el-radio-group>
</el-form-item>
<template v-if="form.data_source_content.data_type == 'appoint'">
<div class="nav-list">
<drag-group :list="form.data_source_content.data_list" :img-params="default_type_data?.appoint_config?.show_data?.data_logo || ''" :title-params="default_type_data?.appoint_config?.show_data?.data_name || 'name'" type="custom" @onsort="data_list_sort" @remove="data_list_remove" @replace="data_list_replace"></drag-group>
<el-button class="mt-20 w" @click="add">+</el-button>
</div>
</template>
<template v-else>
<el-radio :value="1">单行展示</el-radio>
<el-radio :value="2">两行展示</el-radio>
<el-radio :value="3">三行展示</el-radio>
<el-radio :value="4">四行展示</el-radio>
<filter-form :filter-data="default_type_data.filter_config.filter_form_config" direction="vertical" :title-width="70" :data-interface="form.data_source_content" @form-change="filter_form_change"></filter-form>
</template>
</el-radio-group>
</el-form-item>
</card-container>
<div class="divider-line"></div>
<card-container>
<div class="mb-12">{{ form.data_source == 'goods' ? '商品' : form.data_source == 'article' ? '文章' : '品牌' }}设置</div>
<!-- 数据筛选组件, 根据数据源类型显示不同的筛选组件 -->
<data-filter :type="form.data_source" :value="form.data_source_content" :list="form.data_source_content.data_list" :base-list="base_list" @add="add" @data_list_replace="data_list_replace" @data_list_remove="data_list_remove" @data_list_sort="data_list_sort"></data-filter>
</card-container>
</div>
</card-container>
</template>
</template>
<div class="divider-line"></div>
<card-container>
@ -80,21 +83,17 @@
</div>
</div>
</Dialog>
<url-value-dialog v-model:dialog-visible="url_value_dialog_visible" :type="[form.data_source]" :multiple="url_value_multiple_bool" @update:model-value="url_value_dialog_call_back"></url-value-dialog>
<custom-dialog v-model:dialog-visible="url_value_dialog_visible" :config="default_type_data.appoint_config" :multiple="url_value_multiple_bool" @confirm_event="url_value_dialog_call_back"></custom-dialog>
</div>
</template>
<script setup lang="ts">
import Dialog from './components/dialog.vue';
import DragIndex from './components/index.vue';
import { isEmpty, cloneDeep } from 'lodash';
import { isEmpty, cloneDeep, omit } from 'lodash';
import request from '@/utils/request';
import CustomAPI from '@/api/custom';
import ShopAPI from '@/api/shop';
import ArticleAPI from '@/api/article';
import BrandAPI from '@/api/brand';
import { commonStore, DataSourceStore } from '@/store';
import { DataSourceStore } from '@/store';
import { get_math } from '@/utils';
import { source_list } from '@/config/const/custom';
const common_store = commonStore();
const data_source_store = DataSourceStore();
const props = defineProps({
@ -114,8 +113,8 @@ const form = ref(props.value);
const center_width = ref(props.magicWidth);
const custom_width = computed(() => {
// data_source_direction == 2
if (['goods', 'article', 'brand'].includes(form.value.data_source) && form.value.data_source_direction == '2') {
// data_source_direction == horizontal
if (form.value.is_custom_data == '1' && form.value.data_source_direction == 'horizontal') {
return center_width.value / form.value.data_source_carousel_col;
} else {
return center_width.value;
@ -124,12 +123,20 @@ const custom_width = computed(() => {
//
let custom_list = reactive([]);
const center_height = ref(0);
interface custom_config {
show_type: string[],
show_number: number[],
data_type: string[],
filter_config: object,
appoint_config: object,
}
interface data_list {
name: string;
field: string;
type: string;
}
interface options_item {
custom_config?: custom_config;
appoint_data?: object;
name: string;
data: data_list[];
@ -144,6 +151,7 @@ const getCustominit = () => {
data_source_store.set_data_source(data_source);
//
processing_data(form.value.data_source);
data_processing();
});
};
@ -155,8 +163,17 @@ onBeforeMount(() => {
options.value = data_source_store.data_source_list;
//
processing_data(form.value.data_source);
data_processing();
}
});
//
const data_processing = () => {
//
const type_data = options.value.filter((item) => item.type == form.value.data_source);
if (type_data.length > 0 && !isEmpty(type_data[0].custom_config)) {
default_type_data.value = type_data[0].custom_config;
}
};
//
const model_data_source = ref<data_list[]>([]);
const processing_data = (key: string) => {
@ -209,106 +226,82 @@ const accomplish = () => {
//#region
//
const url_value_dialog_visible = ref(false);
const default_type_data = ref<any>({})
const url_value_multiple_bool = ref(true);
const changeDataSource = (key: string) => {
form.value.is_custom_data = '0';
const type_data = options.value.filter((item) => item.type == key);
processing_data(key);
//
form.value.data_source_content = {
// id
data_ids: [],
data_list: [],
//
data_auto_list: [],
}
//
default_type_data.value = {};
form.value.data_source_direction = 'vertical';
// data_list
if (type_data.length > 0 && !isEmpty(type_data[0].appoint_data)) {
form.value.data_source_direction = '0';
form.value.data_source_content = {
// id
data_ids: [],
data_list: [ type_data[0].appoint_data ],
//
data_auto_list: [],
}
} else {
form.value.data_source_content = {
form.value.data_source_content.data_list = [ type_data[0].appoint_data ];
} else if (type_data.length > 0 && !isEmpty(type_data[0].custom_config)) {
//
form.value.is_custom_data = '1';
//
const custom_config = type_data[0].custom_config;
//
form.value.data_source_direction = custom_config.show_type[0];
//
const staging_data : any = {
// id
data_ids: [],
//
data_list: [],
//
data_auto_list: [],
//
data_type: custom_config.data_type[0],
};
if (!isEmpty(key) && key in source_list) {
form.value.data_source_content = cloneDeep(source_list[key as keyof typeof source_list]);
}
//
default_type_data.value = custom_config;
// id
form.value.data_list_key = default_type_data.value?.appoint_config?.show_data?.data_key || 'id';
// ,
default_type_data.value.filter_config.filter_form_config.forEach((item: any) => {
let value : number | string | Array<any> = '';
if (item.type == 'checkbox' || item.type == 'select' && item.config.is_multiple == '1') { //
value = item.config.default ? item.config.default : [];
} else if (item.type == 'input' && item.config.type == 'number') { //
value = item.config.default ? item.config.default : 0;
} else if (item.type == 'switch') {
value = item.config.default ? item.config.default : "0";
}
staging_data[item.form_name] = value;
})
//
form.value.data_source_content = staging_data;
}
};
const filter_form_change = (val: any) => {
form.value.data_source_content = val;
}
//#endregion
//#region
const base_list = reactive({
//
product_list: [
{ name: '指定商品', value: '0' },
{ name: '筛选商品', value: '1' },
],
product_category_list: [] as select_1[],
product_brand_list: [] as select_1[],
sort_list: [
{ name: '综合', value: '0' },
{ name: '销量', value: '1' },
{ name: '热度', value: '2' },
{ name: '价格', value: '3' },
{ name: '最新', value: '4' },
],
//
order_by_rule_list: [
{ name: '降序(desc)', value: '0' },
{ name: '升序(asc)', value: '1' },
],
//
article_category_list: [] as select_1[],
data_type_list: [
{ name: '指定文章', value: '0' },
{ name: '筛选文章', value: '1' },
],
new_sort_list: [
{ name: '综合', value: '0' },
{ name: '时间', value: '1' },
{ name: '浏览量', value: '2' },
],
field_show_list: [
{ name: '日期时间', value: '0' },
{ name: '浏览量', value: '1' },
{ name: '描述', value: '2' },
],
//
brand_category_list: [] as select_1[],
brand_data_type_list: [
{ name: '指定品牌', value: '0' },
{ name: '筛选品牌', value: '1' },
],
brand_sort_list: [
{ name: '最新', value: '0' },
{ name: '热度', value: '1' },
],
});
onBeforeMount(() => {
nextTick(() => {
// common_store.common.article_category
const interval = setInterval(() => {
const { goods_category = [], brand_list = [], article_category = [], brand_category = [] } = common_store.common;
if (goods_category.length > 0 || brand_list.length > 0 || article_category.length > 0) {
base_list.product_category_list = goods_category;
base_list.product_brand_list = brand_list;
base_list.article_category_list = article_category;
base_list.brand_category_list = brand_category;
clearInterval(interval);
}
}, 1000);
});
});
const url_value_multiple_bool = ref(true);
const data_list_replace_index = ref(0);
const data_list_replace = (index: number) => {
// index
data_list_replace_index.value = index;
//
url_value_multiple_bool.value = false;
url_value_dialog_visible.value = true;
};
const add = () => {
url_value_multiple_bool.value = true;
// index-1
data_list_replace_index.value = -1;
//
url_value_multiple_bool.value = default_type_data.value.appoint_config.is_multiple.toString() == '1' ? true : false;
url_value_dialog_visible.value = true;
};
//
@ -325,7 +318,8 @@ const url_value_dialog_call_back = (item: any[]) => {
item.title = item.name;
});
}
if (url_value_multiple_bool.value) {
// data_list_replace_index -1
if (url_value_multiple_bool.value || data_list_replace_index.value == -1) {
item.forEach((item: any) => {
form.value.data_source_content.data_list.push({
id: get_math(),
@ -345,8 +339,8 @@ const url_value_dialog_call_back = (item: any[]) => {
};
//
let data_source_content_list = computed(() => {
if (['goods', 'article', 'brand'].includes(form.value.data_source)) {
if (form.value.data_source_content.data_type == '0') {
if (form.value.is_custom_data == '1') {
if (form.value.data_source_content.data_type == 'appoint') {
return form.value.data_source_content.data_list;
} else {
return form.value.data_source_content.data_auto_list;
@ -356,79 +350,39 @@ let data_source_content_list = computed(() => {
}
})
//
const get_products = () => {
const { category_ids, brand_ids, number, order_by_type, order_by_rule, keyword } = form.value.data_source_content;
const params = {
goods_keywords: keyword,
goods_category_ids: category_ids,
goods_brand_ids: brand_ids,
goods_order_by_type: order_by_type,
goods_order_by_rule: order_by_rule,
goods_number: number,
};
//
ShopAPI.getShopLists(params).then((res: any) => {
//
form.value.data_source_content.data_auto_list = [];
if (!isEmpty(res.data)) {
form.value.data_source_content.data_auto_list = res.data;
}
});
};
//
const get_article = async () => {
const { category_ids, number, order_by_type, order_by_rule, is_cover, keyword } = form.value.data_source_content;
const new_data = {
article_keywords: keyword,
article_category_ids: category_ids.join(','),
article_order_by_type: order_by_type,
article_order_by_rule: order_by_rule,
article_number: number,
article_is_cover: is_cover,
};
const res = await ArticleAPI.getAutoList(new_data);
//
const get_auto_data = () => {
// ,
form.value.data_source_content.data_auto_list = [];
if (!isEmpty(res.data)) {
form.value.data_source_content.data_auto_list = res.data;
if (!isEmpty(default_type_data.value) && !isEmpty(default_type_data.value.filter_config) && !isEmpty(default_type_data.value.filter_config.data_url)) {
const data = omit(cloneDeep(form.value.data_source_content), ['data_ids', 'data_list', 'data_auto_list', 'data_type']);
request({
url: default_type_data.value.filter_config.data_url, //
method: 'post', //
data //
}).then((res) => {
if (res.data) {
form.value.data_source_content.data_auto_list = res.data;
}
})
}
};
//
const get_brand = () => {
const { category_ids, number, order_by_type, order_by_rule, keyword } = form.value.data_source_content;
const params = {
brand_keywords: keyword,
brand_category_ids: category_ids,
brand_order_by_type: order_by_type,
brand_order_by_rule: order_by_rule,
brand_number: number,
};
//
BrandAPI.getBrandLists(params).then((res: any) => {
//
form.value.data_source_content.data_auto_list = [];
if (!isEmpty(res.data)) {
form.value.data_source_content.data_auto_list = res.data;
}
});
form.value.data_source_content.data_auto_list = [];
}
//
const data_source_content_value = computed(() => {
const { category_ids, brand_ids, number, order_by_type, order_by_rule, data_type, is_cover, keyword } = form.value.data_source_content;
return { category_ids: category_ids, brand_ids: brand_ids, number: number, order_by_type: order_by_type, order_by_rule: order_by_rule, data_type: data_type, is_cover: is_cover, keyword: keyword };
})
watch(() => data_source_content_value.value, (new_val) => {
//
if (new_val.data_type != '0') {
if (form.value.data_source == 'goods') {
get_products();
} else if (form.value.data_source == 'article') {
get_article();
} else if (form.value.data_source == 'brand') {
get_brand();
// 'data_ids', 'data_list', 'data_auto_list'
const data: any = {};
for (const key in form.value.data_source_content) {
if (!['data_ids', 'data_list', 'data_auto_list'].includes(key)) {
data[key] = form.value.data_source_content[key];
}
}
return data;
})
//
watch(() => data_source_content_value.value, (new_val, old_val) => {
//
if (JSON.stringify(new_val) != JSON.stringify(old_val) && new_val.data_type != 'appoint') {
get_auto_data();
}
},{ deep: true });
//#endregion
</script>

View File

@ -1,7 +1,7 @@
<template>
<div class="w">
<el-form :model="form" label-width="70">
<template v-if="['1', '2'].includes(data.data_source_direction)">
<template v-if="['vertical-scroll', 'horizontal'].includes(data.data_source_direction)">
<card-container>
<div class="mb-12">轮播设置</div>
<el-form-item label="自动轮播">

View File

@ -77,6 +77,8 @@ interface content {
interface defaultSearch {
content: {
height: number;
is_custom_data: string;
data_list_key: string;
data_source: string;
data_source_content: content;
data_source_direction: string;
@ -114,6 +116,10 @@ const defaultSearch: defaultSearch = {
// 自动
data_auto_list: [],
},
// 手动模式下的唯一标识
data_list_key: '',
// 是否是自定义数据类型
is_custom_data: '0',
// 数据源类型 商品(goods) 文章(article) 品牌(brand) 用户信息(user-info)
data_source:'',
// 铺满方式 0 纵向展示 1 纵向滑动 2 横向滑动

View File

@ -267,4 +267,26 @@ p {
.el-input__wrapper .el-input__inner {
text-align: left;
}
.filter-form-cascader {
.el-checkbox,
.el-radio {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 10;
}
.el-cascader-node {
padding-left: 34px;
}
.el-checkbox__input,
.el-radio__input {
position: absolute;
left: 20px;
}
}

View File

@ -351,11 +351,12 @@ const save_formmat_form_data = (data: diy_data_item, close: boolean = false, is_
} else if (new_array_5.includes(item.key)) {
// data_source_content_value
item.com_data.content = omit(cloneDeep(item.com_data.content), ['data_source_content_value']);
if (['goods', 'article', 'brand'].includes(item.com_data.content.data_source)) {
//
if (item.com_data.content.is_custom_data == '1') {
//
const data_list = cloneDeep(item.com_data.content.data_source_content.data_list);
// ,id
item.com_data.content.data_source_content.data_ids = data_list.map((item: any) => item.data.id || '').join(',') || '';
item.com_data.content.data_source_content.data_ids = data_list.map((item1: any) => item1.data[item.com_data.content?.data_list_key || 'id'] || '').join(',') || '';
// ,data
item.com_data.content.data_source_content.data_list = data_list.map((item1: any) => {
return {