Browse Source

优化组件详情页面

dev-map-local
dai 3 years ago
parent
commit
043fe63972
  1. 976
      src/views/modules/cpts/base/cpts/detail.vue
  2. 67
      src/views/modules/cpts/base/cpts/edit.vue

976
src/views/modules/cpts/base/cpts/detail.vue

@ -1,976 +0,0 @@
<template>
<div>
<div class="dialog-h-content scroll-h">
<el-form
v-if="iniLoaded"
ref="ref_form"
:model="fmData"
:inline="true"
:disabled="formType === 'watch'"
class="m-fm"
:class="editParamsDiv ? 'z-div' : ''"
>
<div class="list">
<el-form-item
v-for="item in editParams"
class="item"
label-width="140px"
style="display: block"
:key="'edit' + item.keyName"
:label="item.field"
:prop="item.keyName"
:rules="item.rules || []"
>
<template v-if="item.type == 'switch'">
<el-switch
v-model="fmData[item.keyName]"
size="small"
:active-text="item.activeText || ''"
:inactive-text="item.inactiveText || ''"
:active-value="item.activeValue || true"
:inactive-value="item.inactiveValue || false"
>
</el-switch>
</template>
<template v-if="item.type == 'input'">
<el-input
v-if="
formType == 'add' || (formType == 'edit' && !item.editDisable)
"
v-model="fmData[item.keyName]"
class="item-input"
size="small"
clearable
show-word-limit
:maxlength="item.maxlength || ''"
:placeholder="item.placeholder || '请输入'"
>
</el-input>
<div class="item-show" v-else>
{{ fmData[item.keyName] || "--" }}
</div>
</template>
<template v-if="item.type == 'textarea'">
<el-input
v-if="
formType == 'add' || (formType == 'edit' && !item.editDisable)
"
v-model="fmData[item.keyName]"
type="textarea"
class="item-input"
size="small"
clearable
show-word-limit
:rows="3"
:maxlength="item.maxlength || ''"
:placeholder="item.placeholder || '请输入'"
>
</el-input>
<div class="item-show" v-else>
{{ fmData[item.keyName] || "--" }}
</div>
</template>
<template v-if="item.type == 'date'">
<el-date-picker
v-if="
formType == 'add' || (formType == 'edit' && !item.editDisable)
"
v-model="fmData[item.keyName]"
:picker-options="item.pickerOptions"
class="item-input"
size="small"
clearable
show-word-limit
:value-format="item.format || 'yyyy-MM-dd'"
:placeholder="item.placeholder || '请输入'"
>
</el-date-picker>
<div class="item-show" v-else>
{{ fmData[item.keyName] || "--" }}
</div>
</template>
<template v-if="item.type == 'number'">
<el-input-number
v-model="fmData[item.keyName]"
class="item-number"
size="small"
clearable
:precision="item.precision || 0"
:step="item.step || 1"
:min="item.min || 0"
:max="item.max || 999999999999"
:placeholder="item.placeholder || '请输入'"
>
</el-input-number>
<span v-if="item.unitName">{{ item.unitName }}</span>
</template>
<template v-else-if="item.type == 'select'">
<el-select
v-model="fmData[item.keyName]"
:placeholder="item.placeholder || '请选择'"
size="small"
clearable
class="item-select"
:multiple="item.multiple || false"
:filterable="item.filterable || false"
:allowCreate="item.allowCreate || false"
:collapse-tags="item.collapseTags || false"
default-first-option
@change="(e) => handleChangeSelect(e, item)"
>
<template v-if="item.optionType == 'group'">
<el-option-group
v-for="group in item.optionList"
:key="group.label"
:label="group.label"
>
<el-option
v-for="subItem in group.optionList"
:key="subItem.value"
:label="subItem.label"
:value="subItem.value"
>
</el-option>
</el-option-group>
</template>
<template v-else>
<el-option
v-for="(subItem, subIndex) in item.optionList"
:key="subItem.value + subIndex"
:label="subItem.label"
:value="subItem.value"
>
</el-option>
</template>
</el-select>
</template>
<template v-else-if="item.type == 'rich-text'">
<div
v-if="
formType == 'add' || (formType == 'edit' && !item.editDisable)
"
class="item-rich-text"
>
<Tinymce
:ref="'richText' + item.keyName"
v-model="fmData[item.keyName]"
:customerId="customerId"
:placeholder="item.placeholder || '请输入'"
:height="500"
/>
</div>
<div
v-else
class="item-rich-text z-show"
@click="handleClickHtmlNode"
>
<div v-html="fmData[item.keyName]"></div>
</div>
</template>
<template v-else-if="item.type == 'cascader'">
<el-cascader
v-model="fmData[item.keyName]"
:placeholder="item.placeholder || '请选择'"
:options="item.optionList"
:props="item.optionProps || {}"
:show-all-levels="false"
:collapse-tags="item.collapseTags || false"
size="small"
clearable
class="item-select"
@change="(e) => handleChangeCascader(e, item)"
>
</el-cascader>
</template>
<template v-else-if="item.type == 'upload'">
<el-upload :headers="$getElUploadHeaders()"
v-if="
formType == 'add' || (formType == 'edit' && !item.editDisable)
"
ref="upload"
class="avatar-uploader"
:class="{ 'z-full': fmData[item.keyName].length >= item.limit }"
:action="item.uploadUrl || uploadUrl"
:data="{ customerId: customerId }"
:show-file-list="true"
:list-type="item.listType || 'picture'"
:limit="item.limit || 100"
:file-list="fmData[item.keyName]"
:on-success="(res, file) => handleImgSuccess(res, file, item)"
:on-error="(res, file) => handleImgError(res, file, item)"
:on-remove="(res) => handleImgRemove(res, item)"
:on-exceed="(res) => handleImgExceed(res, item)"
:before-upload="(file) => beforeImgUpload(file, item)"
>
<a><i class="el-icon-plus"></i> 点击上传</a>
</el-upload>
<el-image
v-else-if="fmData[item.keyName].length > 0"
style="width: 100px; height: 100px"
:src="fmData[item.keyName][0].url"
fit="cover"
:preview-src-list="fmData[item.keyName].map((item) => item.url)"
></el-image>
<span v-else>--</span>
</template>
<template v-else-if="item.type == 'address'">
<div class="address-item">
<el-input
class="address-item-input"
:placeholder="item.placeholder || '请输入所在地址'"
v-model="fmData[item.keyName]"
:maxlength="item.maxlength || ''"
show-word-limit
size="small"
>
</el-input>
<el-button
style="margin-left: 10px"
type="default"
size="small"
ref="mapSearch"
@click="handleSearchMap(item)"
>查询</el-button
>
<div id="app" class="div_map"></div>
<div style="margin-top: 10px" v-show="false">
<span>经度</span>
<el-input
class="address-item-input2"
maxlength="50"
placeholder="请输入经度"
v-model="fmData[item.supKeys[0]]"
>
</el-input>
<span style="margin-left: 20px">纬度</span>
<el-input
class="address-item-input2"
maxlength="50"
placeholder="请输入纬度"
v-model="fmData[item.supKeys[1]]"
>
</el-input>
</div>
</div>
</template>
</el-form-item>
</div>
</el-form>
<div class="div_btn resi-btns" v-if="!formBtnFixed">
<el-button size="small" @click="handleCancle">{{
editConfig.cancelBtnName || "取消"
}}</el-button>
<el-button
v-if="formType != 'watch'"
type="primary"
size="small"
:disabled="btnDisable"
@click="handleComfirm"
>{{ editConfig.confirmBtnName || "确定" }}</el-button
>
<slot
name="operateSup"
v-bind:id="formId"
v-bind:info="fmData"
v-bind:formType="formType"
></slot>
</div>
<slot
name="bottomSup"
v-bind:id="formId"
v-bind:info="fmData"
v-bind:formType="formType"
></slot>
</div>
<div class="div_btn resi-btns" v-if="formBtnFixed">
<el-button size="small" @click="handleCancle">{{
editConfig.cancelBtnName || "取消"
}}</el-button>
<el-button
v-if="formType != 'watch'"
type="primary"
size="small"
:disabled="btnDisable"
@click="handleComfirm"
>{{ editConfig.confirmBtnName || "确定" }}</el-button
>
<slot
name="operateSup"
v-bind:id="formId"
v-bind:info="fmData"
v-bind:formType="formType"
></slot>
</div>
</div>
</template>
<script>
import { requestPost } from "@/js/dai/request";
import nextTick from "dai-js/tools/nextTick";
import Schema from "async-validator";
import Tinymce from "@c/tinymce2/index.vue";
var map;
var search;
var markers;
var infoWindowList;
var geocoder; //
export default {
components: { Tinymce },
props: {
formId: {
type: String,
default: "",
},
formType: {
type: String,
default: "info",
},
formBtnFixed: {
type: Boolean,
default: true,
},
idName: {
type: String,
default: "",
},
addUrl: {
type: String,
default: "",
},
editUrl: {
type: String,
default: "",
},
delUrl: {
type: String,
default: "",
},
infoUrl: {
type: String,
default: "",
},
editParams: {
type: Array,
default: () => [],
},
editFixedParams: {
type: Object,
default: () => ({}),
},
editParamsDiv: {
type: Number,
default: 0,
},
editElseRules: {
type: Object,
default: () => ({}),
},
editConfig: {
type: Object,
default: () => ({}),
},
},
data() {
return {
iniLoaded: false,
btnDisable: false,
fmData: {},
editParams1: [],
editParams2: [],
uploadUrl: window.SITE_CONFIG["apiURL"] + "/oss/file/uploadqrcodeV2",
customerId: localStorage.getItem("customerId"),
};
},
computed: {},
watch: {
editParams: {
handler() {
this.computeFmData();
},
deep: true,
},
},
async mounted() {
this.initForm();
},
methods: {
async initForm() {
this.iniFmData();
if (this.formId && this.formType != "add") {
this.getInfo();
}
},
computeFmData() {
console.log(this.fmData);
},
iniFmData() {
const { editParams, fmData, editParamsDiv } = this;
editParams.forEach((item, index) => {
if (typeof item.value == "function") {
fmData[item.keyName] = item.value();
} else if (
typeof item.value == "string" ||
typeof item.value == "number" ||
typeof item.value == "boolean"
) {
fmData[item.keyName] = item.value;
} else if (typeof item.value == "undefined") {
fmData[item.keyName] = "";
} else {
fmData[item.keyName] = item.value || "";
console.error(
"不应该直接传入数组或对象的值,这样会导致传入的值被子组件修改。editParams-------------cpts/base/cpts/edit.vue",
item
);
}
if (item.supValues) {
item.supValues.forEach((value, index) => {
if (typeof value == "function") {
fmData[item.supKeys[index]] = value();
} else if (
typeof value == "string" ||
typeof value == "number" ||
typeof value == "boolean"
) {
fmData[item.supKeys[index]] = value;
} else if (typeof value == "undefined") {
fmData[item.supKeys[index]] = "";
} else {
fmData[item.supKeys[index]] = value;
console.error(
"不应该直接传入数组或对象的值,这样会导致传入的值被子组件修改。editParams-------------cpts/base/cpts/edit.vue",
item
);
}
});
}
if (item.type == "select" || item.type == "cascader") {
if (item.optionUrl) {
this.getFmOptions(
index,
item.optionUrl,
item.optionUrlParams || {},
item.optionCook || null
);
}
} else if (item.type == "address") {
this.$nextTick(async () => {
await nextTick(300);
this.initMap(item);
});
}
});
this.fmData = { ...fmData };
if (editParamsDiv) {
this.editParams1 = editParams.slice(0, editParamsDiv);
this.editParams2 = editParams.slice(editParamsDiv);
} else {
this.editParams1 = editParams;
}
console.log("------------------------------------", this.fmData);
this.iniLoaded = true;
},
handleClickHtmlNode(e) {
//
if (e.target.localName.toLowerCase() === "a") {
//
let url = e.target.getAttribute("src"); //adata-ididclickaclick
window.open(url);
}
},
async getFmOptions(index, url, params, cookFn) {
const { data, code, msg } = await requestPost(url, {
...params,
});
if (code === 0) {
this.editParams[index].optionList =
typeof cookFn == "function" ? cookFn(data) : data || [];
} else {
this.$message.error("请求检索基础数据失败!");
}
},
handleChangeCascader(vals, item) {
this.fmData[item["keyName"]] = vals;
if (typeof item.handleChangeFn == "function") {
item.handleChangeFn(vals, item, this);
}
},
handleChangeSelect(vals, item) {
console.log(vals, item);
this.fmData[item["keyName"]] = vals;
if (typeof item.handleChangeFn == "function") {
item.handleChangeFn(vals, item, this);
}
},
beforeImgUpload(file, item) {
if (typeof item.beforeImgUpload == "function") {
if (!item.beforeImgUpload(file, item, this)) return false;
}
return true;
},
handleImgRemove(file, item) {
console.log("handleImgRemove", file);
let url = file.response ? file.response.data.url : file.url;
if (url) {
let { fmData } = this;
this.fmData[item.keyName] = fmData[item.keyName].filter(
(item) => item.url !== url
);
if (item.supKeys && Array.isArray(item.supKeys)) {
if (item.supKeys.length > 0) {
this.fmData[item.supKeys[0]] = fmData[item.keyName].map(
(item) => item.url
);
}
if (item.supKeys.length > 1) {
this.fmData[item.supKeys[1]] =
this.fmData[item.supKeys[0]][0] || "";
}
}
}
},
handleImgExceed(res, item) {
console.log(res);
// this.$message({
// type: "warning",
// message: "",
// });
},
handleImgSuccess(res, file, item) {
console.log("handleImgSuccess", res);
if (res.code === 0 && res.msg === "success") {
let { fmData } = this;
// let picItem = {
// url: res.data.url,
// name: file.name,
// size: file.size,
// type: file.type,
// format: file.name.split(".").pop(),
// };
let picItem = file;
picItem.url = res.data.url;
picItem.format = file.name.split(".").pop();
if (Array.isArray(this.fmData[item.keyName])) {
this.fmData[item.keyName].push(picItem);
} else {
this.fmData[item.keyName] = [picItem];
}
if (item.supKeys && Array.isArray(item.supKeys)) {
if (item.supKeys.length > 0) {
this.fmData[item.supKeys[0]] = fmData[item.keyName].map(
(item) => item.url
);
}
if (item.supKeys.length > 1) {
this.fmData[item.supKeys[1]] =
this.fmData[item.supKeys[0]][0] || "";
}
}
} else {
this.$message.error(res.msg);
}
},
handleImgError(res, file, item) {
console.log(res);
},
// init
initMap(item) {
let { latitude, longitude } = this.$store.state.user;
if (!latitude || latitude == "" || latitude == "0") {
latitude = 39.9088810666821;
longitude = 116.39743841556731;
}
//
var center = new window.TMap.LatLng(latitude, longitude);
// map TMap.Map()
map = new window.TMap.Map(document.getElementById("app"), {
center: center, //
zoom: 13, //
pitch: 43.5, //
rotation: 45, //
});
search = new window.TMap.service.Search({ pageSize: 10 });
//
markers = new TMap.MultiMarker({
map: map,
geometries: [],
});
infoWindowList = Array(10);
geocoder = new TMap.service.Geocoder(); //
//
map.on("panend", (e) => {
this.handleMoveCenter(item, e);
});
// this.handleMoveCenter(item);
},
setMarker(lat, lng) {
markers.setGeometries([]);
markers.add([
{
id: "4",
styleId: "marker",
position: new TMap.LatLng(lat, lng),
properties: {
title: "marker4",
},
},
]);
},
handleSearchMap(item) {
infoWindowList.forEach((infoWindow) => {
infoWindow.close();
});
infoWindowList.length = 0;
markers.setGeometries([]);
//
search
.searchRectangle({
keyword: this.fmData[item.keyName],
bounds: map.getBounds(),
})
.then((result) => {
let { data } = result;
if (Array.isArray(data) && data.length > 0) {
const {
location: { lat, lng },
} = data[0];
map.setCenter(new TMap.LatLng(lat, lng));
this.setMarker(lat, lng);
// item.supValues[0] = lng;
// item.supValues[1] = lat;
this.fmData[item.supKeys[0]] = lng;
this.fmData[item.supKeys[1]] = lat;
} else {
this.$message.error("未检索到相关位置坐标");
}
});
},
handleMoveCenter(item, e) {
console.log(e);
//
const center = map.getCenter();
const lat = center.getLat();
const lng = center.getLng();
// item.supValues[0] = lng;
// item.supValues[1] = lat;
this.fmData[item.supKeys[0]] = lng;
this.fmData[item.supKeys[1]] = lat;
this.setMarker(lat, lng);
if (e && e.originalEvent) {
geocoder
.getAddress({ location: new TMap.LatLng(lat, lng) }) //
.then((result) => {
this.fmData[item.keyName] = result.result.address;
});
}
},
async getInfo() {
let url = this.infoUrl;
if (!url) return;
const { idName, formId } = this;
if (url.endsWith("/")) {
url += formId;
}
const params = {
[idName]: formId,
};
let { data, code, msg } = await requestPost(url, params);
if (code === 0) {
const { editConfig } = this;
console.log("xxxxxxxxxxxxxxxxxxxxxx", editConfig);
if (editConfig && typeof editConfig.cookInfoFn == "function") {
data = editConfig.cookInfoFn(data);
}
this.fmData = {
...this.fmData,
...data,
};
await nextTick(600);
if (map) {
if (data.latitude) {
map.setCenter(new TMap.LatLng(data.latitude, data.longitude));
} else {
if (this.formType == "edit" && this.$refs && this.$refs.mapSearch) {
this.$refs.mapSearch[0].handleClick();
}
}
}
} else {
this.$message.error(msg);
}
},
watchImg(src) {
window.open(src);
},
//
dormatHtml(content) {
if (
content.startsWith(
"<!DOCTYPE html>\n<html>\n<head>\n</head>\n<body>\n"
) &&
content.endsWith("\n</body>\n</html>")
) {
content = content.slice(45, -16);
}
return content;
},
cookBeforeSubmit(data) {
Object.keys(data).forEach((k) => {
if (typeof data[k] == "string") {
data[k] = this.dormatHtml(data[k]);
}
});
return data;
},
async handleComfirm() {
this.btnDisable = true;
setTimeout(() => {
this.btnDisable = false;
}, 5000);
console.log(this.$refs["ref_form"]);
this.$refs["ref_form"].validate((valid, messageObj) => {
console.log(valid, messageObj);
if (!valid) {
app.util.validateRule(messageObj);
this.btnDisable = false;
} else {
if (this.editElseRules) {
const validator = new Schema(this.editElseRules);
validator
.validate(this.fmData)
.then(() => {
this.submit();
})
.catch(({ err, fields }) => {
console.log("--------------", err, fields);
app.util.validateRule(fields);
});
} else {
this.submit();
}
}
});
},
async submit() {
const { editConfig, fmData, formType, editFixedParams } = this;
if (
typeof editConfig.beforeSubmit == "function" &&
!editConfig.beforeSubmit(formType, fmData, this)
) {
return;
}
let url = "";
let params = {
...fmData,
...editFixedParams,
// serviceType: this.fmData.serviceTypeArr.join(","),
};
params = this.cookBeforeSubmit(params);
if (this.formType === "add") {
url = this.addUrl;
} else {
url = this.editUrl;
}
const { data, code, msg } = await requestPost(url, params);
if (code === 0) {
this.$message({
type: "success",
message: "操作成功",
});
this.handleCancle();
this.$emit("afterEdit");
this.btnDisable = false;
} else {
this.btnDisable = false;
this.$message.error(msg);
}
},
handleCancle() {
this.$emit("close");
},
},
};
</script>
<style lang="scss" scoped>
.m-fm {
margin-top: 30px;
&.z-div {
.list {
display: flex;
flex-wrap: wrap;
.item {
min-width: 45%;
.item-rich-text {
width: 817px;
max-height: 500px;
overflow: auto;
img {
max-width: 100%;
}
&.z-show {
box-sizing: border-box;
padding: 15px;
border: 1px solid #eee;
height: auto;
}
}
}
}
.item-show {
width: 324px;
}
.item-input {
width: 324px;
}
.item-select {
width: 324px;
}
.item-number {
width: 180px;
}
.address-item {
width: 350px;
.address-item-input {
width: 74%;
}
.address-item-input2 {
margin-left: 5px;
width: 40%;
}
}
}
.avatar-uploader {
&.z-full {
/deep/ .el-upload.el-upload--picture-card {
display: none !important;
}
}
a {
display: flex;
align-items: center;
justify-content: center;
color: #65a5f9;
i {
margin-right: 4px;
color: #65a5f9;
font-size: 18px;
}
&:hover {
text-decoration: none;
}
}
}
.item-rich-text {
width: 600px;
height: 500px;
img {
max-width: 100%;
}
.item-show {
width: 100%;
}
}
.item-select,
.item-show,
.item-input {
width: 450px;
}
.item-number {
width: 225px;
}
.address-item {
width: 450px;
.address-item-input {
width: 85%;
}
.address-item-input2 {
margin-left: 5px;
width: 40%;
}
}
.div_map {
margin-top: 10px;
}
}
</style>

67
src/views/modules/cpts/base/cpts/edit.vue

@ -8,7 +8,7 @@
:inline="true"
:disabled="formType === 'watch'"
class="m-fm"
:class="editParamsDiv ? 'z-div' : ''"
:class="{ 'z-div': editParamsDiv, 'z-watch': formType === 'watch' }"
>
<div class="list">
<el-form-item
@ -98,6 +98,9 @@
<template v-if="item.type == 'number'">
<el-input-number
v-if="
formType == 'add' || (formType == 'edit' && !item.editDisable)
"
v-model="fmData[item.keyName]"
class="item-number"
size="small"
@ -109,6 +112,9 @@
:placeholder="item.placeholder || '请输入'"
>
</el-input-number>
<span class="item-show" v-else>
{{ fmData[item.keyName] || "--" }}
</span>
<span v-if="item.unitName">{{ item.unitName }}</span>
</template>
@ -194,7 +200,8 @@
</template>
<template v-else-if="item.type == 'upload'">
<el-upload :headers="$getElUploadHeaders()"
<el-upload
:headers="$getElUploadHeaders()"
v-if="
formType == 'add' || (formType == 'edit' && !item.editDisable)
"
@ -864,6 +871,60 @@ export default {
.m-fm {
margin-top: 30px;
&.z-watch {
.list {
.item {
}
::v-deep .item {
// placeholder
.el-input.is-disabled .el-input__inner,
.el-textarea.is-disabled textarea.el-textarea__inner {
color: #333;
background-color: rgba(#000, 0);
border-color: rgba(#000, 0);
resize: none;
transform: translateX(-15px);
cursor: default;
&::placeholder {
color: rgba(#fff, 0);
}
}
.el-input.is-disabled .el-input__suffix {
display: none;
}
.el-checkbox.is-disabled.is-checked .el-checkbox__label {
color: #333;
}
.el-form-item__label {
position: relative;
text-align: left;
padding-left: 35px;
&::before {
content: "";
display: block;
position: absolute;
top: 0;
bottom: 0;
left: 20px;
width: 6px;
height: 6px;
margin: auto;
background: #0c81fe;
border-radius: 3px;
margin-right: 10px;
}
&::after {
content: " :";
display: inline;
color: #333;
}
}
}
}
}
&.z-div {
.list {
display: flex;
@ -916,6 +977,7 @@ export default {
}
}
}
.avatar-uploader {
&.z-full {
/deep/ .el-upload.el-upload--picture-card {
@ -938,6 +1000,7 @@ export default {
}
}
}
.item-rich-text {
width: 600px;
height: 500px;

Loading…
Cancel
Save