1.保存数据

sws 2024-08-22
v1.0.0
sws 2024-08-23 17:14:43 +08:00
parent 69a494678c
commit e926edbc5a
8 changed files with 139 additions and 67 deletions

View File

@ -100,7 +100,7 @@ export interface Tree {
/** 路径 */
path: string;
/** 是否开启 */
is_enable: Number;
is_enable: number | string;
/** 排序 */
sort: number;
/** 下级 */

View File

@ -17,7 +17,7 @@
<el-input v-model="form.sort" placeholder="请输入排序"></el-input>
</el-form-item>
<el-form-item label="是否启用">
<el-switch v-model="form.is_enable" :active-value="typeof form.is_enable == 'string' ? '1' : 1" :inactive-value="typeof form.is_enable == 'string' ? '0' : 0"></el-switch>
<el-switch v-model="form.is_enable" active-value="1" inactive-value="0"></el-switch>
</el-form-item>
</el-form>
</div>
@ -67,7 +67,7 @@ const form = ref<Tree>({
name: '',
path: '',
sort: 0,
is_enable: 1,
is_enable: '1',
items: [],
});
watch(
@ -82,7 +82,7 @@ watch(
name: '',
path: '',
sort: 0,
is_enable: 1,
is_enable: '1',
items: [],
};
}

View File

@ -252,8 +252,13 @@ watch(
() => dialog_visible.value,
(val) => {
if (val) {
get_tree();
get_attachment_list();
if (val === true) {
upload_type.value = props.type;
//
get_tree();
//
get_attachment_list();
}
}
}
);

View File

@ -32,5 +32,11 @@ const safe_conten = computed(() => DOMPurify.sanitize(content.value));
.rich-text-content {
white-space: normal;
word-break: break-all;
img {
max-width: 100%;
}
video {
max-width: 100%;
}
}
</style>

View File

@ -2,13 +2,13 @@
<div class="rich-text-content w">
<card-container class="common-content-height">
<div class="mb-12">展示设置</div>
<div class="br-c">
<div class="br-c pr z-deep">
<!-- 工具栏 -->
<Toolbar id="toolbar-container" :editor="editor_ref" :default-config="toolbar_config" :mode="mode" />
<!-- 编辑器 -->
<Editor id="editor-container" v-model="form.html" class="editor" :default-config="editor_config" :mode="mode" @on-change="handle_change" @on-created="handle_created" />
</div>
<upload v-model:model-value="upload_list" v-model:visible-dialog="visibleDialog" is-custom-dialog @update:model-value="upload_list_change"></upload>
<upload v-model:model-value="upload_list" v-model:visible-dialog="visibleDialog" :type="rich_upload_type" is-custom-dialog @update:model-value="upload_list_change"></upload>
</card-container>
</div>
</template>
@ -18,7 +18,7 @@ import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
const props = defineProps({
value: {
type: Object,
default: () => ({ html: '' }),
default: () => ({ html: '<p></p>' }),
},
});
const form = reactive(props.value);
@ -26,9 +26,15 @@ const form = reactive(props.value);
const mode = ref('default'); //
// shallowRef
const editor_ref = shallowRef();
//
const cursor_position = ref(0);
const toolbar_config = ref({}); //
//
const upload_list = ref<uploadList[]>([]);
//
const visibleDialog = ref(false);
//
const rich_upload_type = ref('img');
//
interface InsertFnType {
(url: string, alt?: string, href?: string): void;
@ -36,10 +42,21 @@ interface InsertFnType {
const editor_config = ref({
placeholder: '请输入内容...',
MENU_CONF: {
//
uploadImage: {
//
customBrowseAndUpload(insertFn: InsertFnType) {
rich_upload_type.value = 'img';
visibleDialog.value = true;
cursor_position.value = editor_ref.value.selection;
},
},
uploadVideo: {
//
customBrowseAndUpload(insertFn: InsertFnType) {
rich_upload_type.value = 'video';
visibleDialog.value = true;
cursor_position.value = editor_ref.value.selection;
},
},
},
@ -53,16 +70,26 @@ const handle_change = (editor: any) => {
form.html = editor.getHtml();
};
const upload_list_change = (arry: uploadList[]) => {
console.log(arry);
const editor = editor_ref.value;
let new_html = '';
if (editor) {
arry.forEach((item: uploadList) => {
const url = item.url;
const alt = item.title;
new_html += `<img src="${url}" alt="${alt}" />`;
if (rich_upload_type.value === 'img') {
new_html += `<img src="${url}" alt="${alt}" />`;
} else if (rich_upload_type.value === 'video') {
new_html += `<video src="${url}" />`;
}
});
editor.setHtml(new_html);
//
console.log(editor);
// if (editor.isDisabled()) editor.enable();
// if (!editor.isFocused()) editor.focus();
// editor.select(cursor_position.value);
// // editor.deleteFragment();
editor.dangerouslyInsertHtml(new_html);
}
upload_list.value = [];
};
@ -79,6 +106,12 @@ onBeforeUnmount(() => {
position: relative;
height: calc(100vh - 42.5rem) !important;
overflow-y: hidden;
img {
max-width: 100%;
}
video {
max-width: 100%;
}
}
}
</style>

View File

@ -5,28 +5,12 @@
<icon name="arrow-left" color="f">返回</icon>
<div class="flex-row align-c">
<div class="name">
<div class="flex-row align-c gap-10">
<div @click="open_dialog">
<image-empty :src="modelValue.img" class="round img" error-img-style="width: 2.2rem;height: 2.2rem;" />
</div>
<div class="flex-row align-c gap-10 c-pointer" @click="dialog_visible = true">
<image-empty :src="modelValue.logo" class="round img" error-img-style="width: 2.2rem;height: 2.2rem;" />
<div>{{ modelValue.name }}</div>
<div class="hide">
<upload v-model="file_img" :visible-dialog="is_dialog_visible" :limit="1" :size="44" :styles="1" @update:visible-dialog="is_dialog_visible = $event" @update:model-value="file_img_update"></upload>
</div>
<icon name="edit" color="primary"></icon>
</div>
</div>
<el-popover v-model:visible="visible" trigger="click" :width="300">
<div class="flex-row align-c gap-10">
<el-input v-model="name" placeholder="请输入模版名称" />
<div class="flex-row">
<el-button size="small" text @click="visible = false">取消</el-button>
<el-button size="small" type="primary" @click="modules_name"></el-button>
</div>
</div>
<template #reference>
<icon name="edit" color="primary"></icon>
</template>
</el-popover>
</div>
</div>
<div class="nav-right">
@ -36,39 +20,58 @@
<el-button class="btn-white" @click="save_close_event"></el-button>
</div>
</div>
<upload v-model:visible-dialog="is_custom_dialog" is-custom-dialog :is-check-confirm="false"></upload>
<el-dialog v-model="dialog_visible" class="radius-lg" width="650" draggable append-to-body>
<template #header>
<div class="title re">
<div class="middle size-16 fw">附件管理</div>
</div>
</template>
<div class="content pa-20">
<el-form ref="ruleFormRef" :model="form" :rules="rules" label-width="70" status-icon>
<el-form-item label="上传头像">
<upload v-model="form.logo" :limit="1"></upload>
</el-form-item>
<el-form-item label="模版名称" prop="name">
<el-input v-model="form.name" placeholder="请输入模版名称" />
</el-form-item>
<el-form-item label="模版描述">
<el-input v-model="form.describe" placeholder="请输入模版描述" :rows="4" type="textarea" />
</el-form-item>
<el-form-item label="模版开关">
<el-switch v-model="form.is_enable" active-value="1" inactive-value="0"></el-switch>
</el-form-item>
</el-form>
</div>
<template #footer>
<span class="dialog-footer">
<el-button class="plr-28 ptb-10" @click="dialog_visible = false">取消</el-button>
<el-button class="plr-28 ptb-10" type="primary" @click="confirm_event(ruleFormRef)"></el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { FormInstance, FormRules } from 'element-plus';
const modelValue = defineModel({ type: Object, default: {} });
// #region --------------------start
const visible = ref(false);
const name = ref('');
const file_img = ref([]);
const is_dialog_visible = ref(false);
const is_custom_dialog = ref(false);
const dialog_visible = ref(false);
const form = ref({
logo: modelValue.value.logo.length > 0 ? [{ url: modelValue.value.logo }] : [],
name: modelValue.value.name,
describe: modelValue.value.describe,
is_enable: modelValue.value.is_enable,
});
const ruleFormRef = ref<FormInstance>();
const rules = reactive<FormRules>({
name: [
{ required: true, trigger: 'blur', message: '请输入模版名称' },
{ min: 1, max: 60, message: '名称长度1~60个字符', trigger: 'blur' },
],
});
// #endregion --------------------end
/**
* 修改模版名称
*/
const modules_name = () => {
if (name.value) {
modelValue.value.name = name.value;
visible.value = false;
}
};
const emit = defineEmits(['preview', 'save', 'saveClose']);
// #region --------------------start
const open_dialog = () => {
is_dialog_visible.value = true;
};
const file_img_update = (file: any) => {
modelValue.value.img = file[0].url;
};
// #endregion --------------------end
//
const upload_manage = () => {
is_custom_dialog.value = true;
@ -87,6 +90,21 @@ const save_event = () => {
const save_close_event = () => {
emit('saveClose');
};
const confirm_event = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
await formEl.validate((valid, fields) => {
if (valid) {
dialog_visible.value = false;
modelValue.value = {
...form.value,
logo: form.value.logo.length > 0 ? form.value.logo[0].url : '',
};
} else {
console.log('error submit!', fields);
}
});
};
</script>
<style lang="scss" scoped>
.navbar {

View File

@ -27,19 +27,22 @@ interface headerAndFooter {
interface diy_data_item {
id: string;
model: {
img: string;
logo: string;
name: string;
is_enable: string;
describe: string;
};
header: headerAndFooter;
footer: headerAndFooter;
diy_data: Array<any>;
is_enable: string;
}
const form = ref<diy_data_item>({
id: '',
model: {
img: '',
logo: '',
name: '',
is_enable: '1',
describe: '',
},
header: {
name: '页面设置',
@ -54,7 +57,6 @@ const form = ref<diy_data_item>({
com_data: defaultSettings.footer_nav,
},
diy_data: [],
is_enable: '1',
});
const diy_data_item = ref({});
@ -135,15 +137,15 @@ const formmat_form_data = (data: diy_data_item) => {
const diy_data_transfor_form_data = (clone_form: diy_data_item) => {
return {
id: clone_form.id,
logo: clone_form.model.img,
logo: clone_form.model.logo,
name: clone_form.model.name,
describe: '',
is_enable: clone_form.model.is_enable,
describe: clone_form.model.describe,
config: JSON.stringify({
header: clone_form.header,
footer: clone_form.footer,
diy_data: clone_form.diy_data,
}),
is_enable: clone_form.is_enable,
};
};
const form_data_transfor_diy_data = (clone_form: diyData) => {
@ -151,25 +153,27 @@ const form_data_transfor_diy_data = (clone_form: diyData) => {
return {
id: clone_form.id,
model: {
img: clone_form.logo,
logo: clone_form.logo,
name: clone_form.name,
is_enable: clone_form.is_enable,
describe: clone_form.describe,
},
header: JSON.parse(clone_form.config).header,
footer: JSON.parse(clone_form.config).footer,
diy_data: JSON.parse(clone_form.config).diy_data,
is_enable: clone_form.is_enable,
};
} catch (error) {
return {
id: clone_form.id,
model: {
img: clone_form.logo,
logo: clone_form.logo,
name: clone_form.name,
is_enable: clone_form.is_enable,
describe: clone_form.describe,
},
header: form.value.header,
footer: form.value.footer,
diy_data: form.value.diy_data,
is_enable: clone_form.is_enable,
};
}
};

View File

@ -196,6 +196,12 @@
.z-i {
z-index: 1;
}
.z-deep {
z-index: 2;
}
.z-top {
z-index: 9;
}
//
.oh {