檢查fb yt連結格式

main
Wayne Hsu 3 years ago
parent dbd372816a
commit 8a7fac2d0f

11676
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -28,7 +28,7 @@
"register-service-worker": "^1.7.1",
"secure-ls": "^1.2.6",
"vant": "^3.4.5",
"vue": "^3.0.0",
"vue": "3.2.41",
"vue-advanced-cropper": "^2.8.1",
"vue-cropper": "^1.0.3",
"vue-router": "^4.0.0-0",
@ -41,7 +41,7 @@
"@vue/cli-plugin-router": "~4.5.15",
"@vue/cli-plugin-vuex": "~4.5.15",
"@vue/cli-service": "~4.5.15",
"@vue/compiler-sfc": "^3.0.0",
"@vue/compiler-sfc": "3.2.41",
"babel-plugin-import": "^1.13.3",
"less": "^3.0.4",
"less-loader": "^5.0.0"

@ -1,84 +1,205 @@
<template>
<div class="member-container">
<van-nav-bar title="個人資料修改" right-text="" @click-right="$router.push('/')" />
<van-nav-bar
title="個人資料修改"
right-text="關閉"
@click-right="$router.push('/')"
/>
<van-tabs :lazy-render="true" v-model:active="active">
<van-tab title="基本資料">
</van-tab>
<van-tab title="公司資料">
</van-tab>
<van-tab title="更多連結">
</van-tab>
<van-tab title="基本資料"> </van-tab>
<van-tab title="公司資料"> </van-tab>
<van-tab title="更多連結"> </van-tab>
</van-tabs>
<van-form @submit="onSubmit">
<van-cell-group inset v-show="active === 0">
<van-field v-model="form.real_name" label="姓名" name="pattern" placeholder="請輸入您的姓名"
:rules="[{ required: true, message: '姓名為必填' }]" />
<van-field v-model="form.phone" label="手機" name="" type="tel" placeholder="Ex. 0900000001 不要有空格"
:rules="[{ required: true, message: '手機號必填' }, { pattern: /\d{10}/, message: '手機號格式錯誤' }]" />
<van-field v-model="form.email" label="Email" name="" placeholder="請輸入您的Email"
:rules="[{ required: true, message: 'Email必填' }, { pattern: /^([\w\.\-]){1,64}\@([\w\.\-]){1,64}/, message: 'Email格式錯誤' }]" />
<van-field
v-model="form.real_name"
label="姓名"
name="pattern"
placeholder="請輸入您的姓名"
:rules="[{ required: true, message: '姓名為必填' }]"
/>
<van-field
v-model="form.phone"
label="手機"
name=""
type="tel"
placeholder="Ex. 0900000001 不要有空格"
:rules="[
{ required: true, message: '手機號必填' },
{ pattern: /\d{10}/, message: '手機號格式錯誤' },
]"
/>
<van-field
v-model="form.email"
label="Email"
name=""
placeholder="請輸入您的Email"
:rules="[
{ required: true, message: 'Email必填' },
{
pattern: /^([\w\.\-]){1,64}\@([\w\.\-]){1,64}/,
message: 'Email格式錯誤',
},
]"
/>
<!-- <van-field v-model="form.url" label="網址" name="" placeholder="請輸入您的網址"
:rules="[{ validator: validatorUrl, message: '網址格式不正確,Ex. http://' }]" /> -->
<van-field v-model="form.line" label="Line" name="" placeholder="請輸入您的Line ID" />
<van-field v-model="form.facebook" label="Facebook" name="" placeholder="請輸入您的臉書連結" />
<van-field v-model="form.ig" label="IG" name="" placeholder="請輸入您的IG ID" />
<van-field v-model="form.youtube" label="YouTube" name="" placeholder="請輸入您的Youtube連結" />
<van-field v-model="form.mark" rows="3" autosize label="簡介" type="textarea" maxlength="100" placeholder="請輸入簡介"
show-word-limit />
<van-field
v-model="form.line"
label="Line"
name=""
placeholder="請輸入您的Line ID"
/>
<van-field
v-model="form.facebook"
label="Facebook"
name=""
placeholder="請輸入您的臉書連結"
:rules="[
{
validator: validatorUrl,
message: '臉書連結格式不正確,https://...',
},
]"
/>
<van-field
v-model="form.ig"
label="IG"
name=""
placeholder="請輸入您的IG ID"
/>
<van-field
v-model="form.youtube"
label="YouTube"
name=""
placeholder="請輸入您的Youtube連結"
:rules="[
{
validator: validatorUrl,
message: '連結格式不正確,https://...',
},
]"
/>
<van-field
v-model="form.mark"
rows="3"
autosize
label="簡介"
type="textarea"
maxlength="100"
placeholder="請輸入簡介"
show-word-limit
/>
<van-uploader :after-read="afterRead" :max-count="1" name="aveter">
<div class="upload-main">
<img class="upload-img" :src="form.avatar" alt="">
<img class="upload-img" :src="form.avatar" alt="" />
<p>上傳圖片</p>
</div>
</van-uploader>
</van-cell-group>
<main class="main-wrap address2-page mb-xxl" v-show="active === 1">
<div class="add-btn">
<van-button type="success" plain hairline block @click="handleAddUserCompany">+</van-button>
<van-button
type="success"
plain
hairline
block
@click="handleAddUserCompany"
>+新增公司資料</van-button
>
</div>
<div class="address-wrap">
<div class="address-box"
:class="{active: uc.is_default}"
v-for="(uc,index) in userCompany"
:key="uc.id"
@click="handleSetDefault(uc.id)">
<div class="conten-box">
<div class="heading">
<div class="heading-left">
<span class="title title-color font-md">{{ uc.uc_name }}</span>
<span class="badges-round font-white bg-theme-theme font-xs" v-if="uc.is_default"></span>
</div>
<div class="heading-right">
<i class="icon-pencil" @click.stop="handleEdit(uc.id)"></i>
<i class="icon-trash" style="color: red;" @click.stop="handleDelete(uc.id)"></i>
<div
class="address-box"
:class="{ active: uc.is_default }"
v-for="(uc, index) in userCompany"
:key="uc.id"
@click="handleSetDefault(uc.id)"
>
<div class="conten-box">
<div class="heading">
<div class="heading-left">
<span class="title title-color font-md">{{
uc.uc_name
}}</span>
<span
class="badges-round font-white bg-theme-theme font-xs"
v-if="uc.is_default"
>預設</span
>
</div>
<div class="heading-right">
<i class="icon-pencil" @click.stop="handleEdit(uc.id)"></i>
<i
class="icon-trash"
style="color: red"
@click.stop="handleDelete(uc.id)"
></i>
</div>
</div>
<h3 class="title-color font-sm">{{ uc.uc_title }}</h3>
<h3 class="title-color font-sm">{{ uc.uc_tel }}</h3>
<p class="content-color font-sm">{{ uc.uc_address }}</p>
</div>
<h3 class="title-color font-sm">{{ uc.uc_title }}</h3>
<h3 class="title-color font-sm">{{ uc.uc_tel }}</h3>
<p class="content-color font-sm">{{ uc.uc_address }}</p>
<!-- <img src="/src/assets/images/map/map.jpg" alt="map" /> -->
</div>
<!-- <img src="/src/assets/images/map/map.jpg" alt="map" /> -->
</div>
</div>
</main>
<van-cell-group inset v-show="active === 2" v-for="(v, idx) in form.addon" :key="idx">
<van-cell-group
inset
v-show="active === 2"
v-for="(v, idx) in form.addon"
:key="idx"
>
<div class="act-btn">
<van-button type="primary" icon="arrow-up" plain hairline @click="onMoveBtn(0, idx)">上移</van-button>
<van-button type="primary" icon="arrow-down" plain hairline @click="onMoveBtn(1, idx)">下移</van-button>
<van-button type="danger" icon="delete-o" plain hairline @click="onDelBtn(idx)"></van-button>
<van-button
type="primary"
icon="arrow-up"
plain
hairline
@click="onMoveBtn(0, idx)"
>上移</van-button
>
<van-button
type="primary"
icon="arrow-down"
plain
hairline
@click="onMoveBtn(1, idx)"
>下移</van-button
>
<van-button
type="danger"
icon="delete-o"
plain
hairline
@click="onDelBtn(idx)"
>刪除</van-button
>
</div>
<!-- <div class="field">
<div class="label">圖示</div>
<div class="content"><i class="iconfont icon-home"></i><span style="padding: 0 10px" @click="showChangeIcon=true"></span></div>
</div> -->
<van-field label="名稱" name="" v-model="form.addon[idx].name" placeholder="按鈕名稱" />
<van-field label="連結" name="" v-model="form.addon[idx].link" placeholder="按鈕連結" />
<van-field
label="名稱"
name=""
v-model="form.addon[idx].name"
placeholder="按鈕名稱"
/>
<van-field
label="連結"
name=""
v-model="form.addon[idx].link"
placeholder="按鈕連結"
/>
</van-cell-group>
<div class="add-btn" v-show="active === 2" @click="onAddBtn">
<van-button type="success" plain hairline block>+新增按鈕</van-button>
</div>
<div style="margin: 16px;">
<div style="margin: 16px">
<van-button round block type="primary" native-type="submit">
送出
</van-button>
@ -107,21 +228,30 @@
<div class="icon-item">
<i class="iconfont icon-home" style="font-size: 40px"></i>
</div>
<div class="icon-item">
</div>
<div class="icon-item"></div>
</div>
</van-popup>
<Footer />
<van-overlay :show="crop.show" @click="crop.show = false" />
<div class="cropper-section" v-if="crop.show">
<div class="crop-area">
<cropper class="cropper" ref="myCrop" :src="crop.img" :stencil-props="{
aspectRatio: 1 / 1
}" :auto-zoom="true" />
<cropper
class="cropper"
ref="myCrop"
:src="crop.img"
:stencil-props="{
aspectRatio: 1 / 1,
}"
:auto-zoom="true"
/>
</div>
<div class="crop-btn">
<van-button type="primary" size="small" plain @click="onClose"></van-button>
<van-button type="success" size="small" plain @click="onCrop"></van-button>
<van-button type="primary" size="small" plain @click="onClose"
>取消</van-button
>
<van-button type="success" size="small" plain @click="onCrop"
>剪裁</van-button
>
</div>
</div>
</div>
@ -133,14 +263,45 @@
<van-form @submit="onUCSumbit" ref="addrForm">
<div class="offcanvas-body small">
<van-cell-group inset>
<van-field v-model="ucForm.uc_name" label="公司名稱" placeholder="請輸入您的公司名稱"
:rules="[{ required: true, message: '公司名稱必填' }]" />
<van-field v-model="ucForm.uc_title" label="職稱" placeholder="請輸入您的職稱" />
<van-field v-model="ucForm.uc_tel" label="公司電話" type="tel" placeholder="請輸入您的市話"
:rules="[{ validator: validatorTel, message: '市話格式不正確,Ex. 02xxxx or 02-xxxx' }]" />
<van-field v-model="ucForm.uc_address" label="公司住址" placeholder="請輸入您的地址" />
<van-field v-model="ucForm.uc_url" label="公司網址" placeholder="請輸入您的網址"
:rules="[{ validator: validatorUrl, message: '網址格式不正確,Ex. http://' }]" />
<van-field
v-model="ucForm.uc_name"
label="公司名稱"
placeholder="請輸入您的公司名稱"
:rules="[{ required: true, message: '公司名稱必填' }]"
/>
<van-field
v-model="ucForm.uc_title"
label="職稱"
placeholder="請輸入您的職稱"
/>
<van-field
v-model="ucForm.uc_tel"
label="公司電話"
type="tel"
placeholder="請輸入您的市話"
:rules="[
{
validator: validatorTel,
message: '市話格式不正確,Ex. 02xxxx or 02-xxxx',
},
]"
/>
<van-field
v-model="ucForm.uc_address"
label="公司住址"
placeholder="請輸入您的地址"
/>
<van-field
v-model="ucForm.uc_url"
label="公司網址"
placeholder="請輸入您的網址"
:rules="[
{
validator: validatorUrl,
message: '網址格式不正確,Ex. http://',
},
]"
/>
<van-field name="is_default" label="是否為預設">
<template #input>
<van-switch v-model="ucForm.is_default" />
@ -148,7 +309,7 @@
</van-field>
</van-cell-group>
</div>
<div style="margin: 16px;">
<div style="margin: 16px">
<van-button round block type="primary" native-type="submit">
新增
</van-button>
@ -156,312 +317,278 @@
</van-form>
</van-popup>
<!-- Add New Address Off Canvas End -->
</template>
<script>
import _ from 'lodash'
import axios from 'axios'
import Cookies from 'js-cookie'
<script setup>
import _ from "lodash";
import axios from "axios";
import Cookies from "js-cookie";
import { ref, nextTick } from 'vue'
import { ref, nextTick } from "vue";
import { Cropper } from 'vue-advanced-cropper';
import 'vue-advanced-cropper/dist/style.css';
import { Cropper } from "vue-advanced-cropper";
import "vue-advanced-cropper/dist/style.css";
import Footer from '@/components/Footer'
import { useStore } from 'vuex'
import { useRouter } from 'vue-router'
import Footer from "@/components/Footer";
import { useStore } from "vuex";
import { useRouter } from "vue-router";
import { Toast } from 'vant'
import { Toast } from "vant";
import {
getUserInfo,
updateCard,
getUserCompany,
addUserCompany,
updateUserCompany,
deleteUserCompany,
setUCDefault
} from '@/api/user'
import { is } from '@babel/types';
import {
getUserInfo,
updateCard,
getUserCompany,
addUserCompany,
updateUserCompany,
deleteUserCompany,
setUCDefault,
} from "@/api/user";
import { is } from "@babel/types";
const URL = window.URL || window.webkitURL;
export default {
name: 'EditForm',
components: {
Footer,
Cropper
},
async setup() {
const store = useStore()
const router = useRouter()
const store = useStore();
const router = useRouter();
const form = ref({ addon: [] })
const form = ref({ addon: [] });
const userCompany = ref([])
const userCompany = ref([]);
const ucForm = ref({
action: 'insert',
uc_name: '',
uc_title: '',
uc_tel: '',
uc_address: '',
uc_url: '',
})
const ucForm = ref({
action: "insert",
uc_name: "",
uc_title: "",
uc_tel: "",
uc_address: "",
uc_url: "",
});
const fileList = ref([]);
const fileList = ref([]);
const myCrop = ref(null)
const myCrop = ref(null);
const active = ref(0)
const active = ref(0);
const showChangeIcon = ref(false)
const showChangeIcon = ref(false);
const showOffcanvas = ref(false)
const showOffcanvas = ref(false);
const crop = ref({
show: false,
img: null,
})
const crop = ref({
show: false,
img: null,
});
const validatorUrl = (val) => {
if (val.length > 0) {
return /(https?:\/\/|line:\/\/|tel:|mailto:)\S+/.test(val)
} else {
return true
}
};
const validatorUrl = (val) => {
if (val.length > 0) {
return /(https?:\/\/|line:\/\/|tel:|mailto:)\S+/.test(val);
} else {
return true;
}
};
const validatorTel = (val) => {
if (val.length > 0) {
return /(\d{2,3}-?|\(\d{2,3}\))\d{3,4}-?\d{4}/.test(val)
} else {
return true
}
};
const validatorTel = (val) => {
if (val.length > 0) {
return /(\d{2,3}-?|\(\d{2,3}\))\d{3,4}-?\d{4}/.test(val);
} else {
return true;
}
};
// onMounted(async ()=>{
let userRes = await getUserInfo();
if (userRes.code === 200) {
form.value = userRes.data;
} else {
}
// })
if (userRes.data.nfc_addon && userRes.data.nfc_addon.length > 0) {
form.value.addon = JSON.parse(userRes.data.nfc_addon);
}
// onMounted(async ()=>{
let userRes = await getUserInfo()
if (userRes.code === 200) {
form.value = userRes.data
} else {
const onCrop = () => {
const { canvas } = myCrop.value.getResult();
if (canvas) {
const imgFile = new FormData();
canvas.toBlob(async (blob) => {
let ufile = new File([blob], "image.jpg");
imgFile.append("user_id", form.value.user_id);
imgFile.append("fileType", "IMAGE");
imgFile.append("file", ufile);
}
// })
if (userRes.data.nfc_addon && (userRes.data.nfc_addon.length > 0)) {
form.value.addon = JSON.parse(userRes.data.nfc_addon)
}
crop.value.show = false;
const onCrop = () => {
const { canvas } = myCrop.value.getResult();
if (canvas) {
const imgFile = new FormData();
canvas.toBlob(async (blob) => {
let ufile = new File([blob], "image.jpg");
imgFile.append("user_id", form.value.user_id)
imgFile.append("fileType", "IMAGE")
imgFile.append('file', ufile)
crop.value.show = false
Toast.loading({
duration: 0,
message: '圖片上傳中...',
forbidClick: true,
});
let res = await axios.post(
`${process.env.VUE_APP_API_URL}/user/uploadAvatar`,
imgFile,
{
}
)
Toast.loading({
duration: 0,
message: "圖片上傳中...",
forbidClick: true,
});
if (res.data.code == 200) {
form.value.avatar = res.data.data
Toast.success('上傳成功');
} else {
Toast.fail('上傳失敗');
}
let res = await axios.post(
`${process.env.VUE_APP_API_URL}/user/uploadAvatar`,
imgFile,
{}
);
}, 'image/jpeg');
if (res.data.code == 200) {
form.value.avatar = res.data.data;
Toast.success("上傳成功");
} else {
Toast.fail("上傳失敗");
}
}, "image/jpeg");
}
return
}
const onClose = () => {
crop.value.show = false
}
const afterRead = async (file, name) => {
crop.value.show = true
const ofile = file.file
crop.value.img = URL.createObjectURL(ofile);
// crop.value.img = ofile
return
};
//
let userCompRes = await getUserCompany()
if (userCompRes.code === 200) {
userCompany.value = userCompRes.data
}
console.log(userCompany.value)
return;
};
//
const onAddBtn = () => {
if (form.value.addon) {
form.value.addon.push({ icon: '', name: '', link: '' })
} else {
form.value.addon = [{ icon: '', name: '', link: '' }]
}
}
const onClose = () => {
crop.value.show = false;
};
const onDelBtn = (index) => {
form.value.addon.splice(index, 1)
}
const afterRead = async (file, name) => {
crop.value.show = true;
const onMoveBtn = (type, index) => {
if (type === 0) {
if (index !== 0) {
[form.value.addon[index], form.value.addon[index - 1]] = [form.value.addon[index - 1], form.value.addon[index]]
}
} else {
if (index + 1 !== form.value.addon.length) {
[form.value.addon[index + 1], form.value.addon[index]] = [form.value.addon[index], form.value.addon[index + 1]]
}
}
const ofile = file.file;
crop.value.img = URL.createObjectURL(ofile);
// crop.value.img = ofile
return;
};
//
let userCompRes = await getUserCompany();
if (userCompRes.code === 200) {
userCompany.value = userCompRes.data;
}
console.log(userCompany.value);
//
const onAddBtn = () => {
if (form.value.addon) {
form.value.addon.push({ icon: "", name: "", link: "" });
} else {
form.value.addon = [{ icon: "", name: "", link: "" }];
}
};
const onDelBtn = (index) => {
form.value.addon.splice(index, 1);
};
const onMoveBtn = (type, index) => {
if (type === 0) {
if (index !== 0) {
[form.value.addon[index], form.value.addon[index - 1]] = [
form.value.addon[index - 1],
form.value.addon[index],
];
}
const handleAddUserCompany = () => {
ucForm.value = {action: 'insert'}
console.log(userCompany.value.length,userCompany.value)
if(userCompany.value.length ==0){
ucForm.value.is_default = true
}
showOffcanvas.value = true
} else {
if (index + 1 !== form.value.addon.length) {
[form.value.addon[index + 1], form.value.addon[index]] = [
form.value.addon[index],
form.value.addon[index + 1],
];
}
}
};
const handleSetDefault = async (id) => {
let res = await setUCDefault(id)
if(res.code === 200){
userCompany.value = res.data
}else{
Toast('操作失敗')
}
}
const onUCSumbit = async () => {
if(ucForm.value.action ==='insert'){
if(userCompany.length === 0){
ucForm.value.is_default = true
}
let res = await addUserCompany(ucForm.value)
if(res.code === 200){
ucForm.value={
uc_name: '',
uc_title: '',
uc_tel: '',
uc_address: '',
uc_url: ''
}
showOffcanvas.value = false
userCompany.value = res.data
}else{
Toast('操作失敗')
}
}else{
let res = await updateUserCompany(ucForm.value)
if(res.code === 200){
ucForm.value={
uc_name: '',
uc_title: '',
uc_tel: '',
uc_address: '',
uc_url: ''
}
showOffcanvas.value = false
userCompany.value = res.data
}else{
Toast('操作失敗')
}
}
}
const handleAddUserCompany = () => {
ucForm.value = { action: "insert" };
console.log(userCompany.value.length, userCompany.value);
if (userCompany.value.length == 0) {
ucForm.value.is_default = true;
}
showOffcanvas.value = true;
};
const handleSetDefault = async (id) => {
let res = await setUCDefault(id);
if (res.code === 200) {
userCompany.value = res.data;
} else {
Toast("操作失敗");
}
};
const handleDelete = async (id)=>{
let res = await deleteUserCompany(id)
if(res.code === 200){
userCompany.value = res.data
}else{
Toast('操作失敗')
}
const onUCSumbit = async () => {
if (ucForm.value.action === "insert") {
if (userCompany.length === 0) {
ucForm.value.is_default = true;
}
const handleEdit = async (id)=>{
showOffcanvas.value = true
let t_data = {action:'update',...userCompany.value.find(item => item.id == id)}
if(t_data.is_default==1){
t_data.is_default=true
}else{
t_data.is_default=false
}
ucForm.value = t_data
let res = await addUserCompany(ucForm.value);
if (res.code === 200) {
ucForm.value = {
uc_name: "",
uc_title: "",
uc_tel: "",
uc_address: "",
uc_url: "",
};
showOffcanvas.value = false;
userCompany.value = res.data;
} else {
Toast("操作失敗");
}
const onSubmit = async () => {
Toast.loading({
duration: 0,
message: '資料更新中...',
forbidClick: true,
});
let res = await updateCard(form.value)
if (res.code === 200) {
Toast.success('更新成功')
store.commit('user/setUserInfo', form.value)
router.push('/')
} else {
Toast.fail('更新失敗')
}
};
return {
form,
fileList,
crop,
myCrop,
active,
userCompany,
ucForm,
showChangeIcon,
showOffcanvas,
onAddBtn,
onDelBtn,
onMoveBtn,
validatorUrl,
validatorTel,
onCrop,
onClose,
afterRead,
onSubmit,
onUCSumbit,
handleEdit,
handleDelete,
handleSetDefault,
handleAddUserCompany
} else {
let res = await updateUserCompany(ucForm.value);
if (res.code === 200) {
ucForm.value = {
uc_name: "",
uc_title: "",
uc_tel: "",
uc_address: "",
uc_url: "",
};
showOffcanvas.value = false;
userCompany.value = res.data;
} else {
Toast("操作失敗");
}
}
}
};
const handleDelete = async (id) => {
let res = await deleteUserCompany(id);
if (res.code === 200) {
userCompany.value = res.data;
} else {
Toast("操作失敗");
}
};
const handleEdit = async (id) => {
showOffcanvas.value = true;
let t_data = {
action: "update",
...userCompany.value.find((item) => item.id == id),
};
if (t_data.is_default == 1) {
t_data.is_default = true;
} else {
t_data.is_default = false;
}
ucForm.value = t_data;
};
const onSubmit = async () => {
Toast.loading({
duration: 0,
message: "資料更新中...",
forbidClick: true,
});
let res = await updateCard(form.value);
if (res.code === 200) {
Toast.success("更新成功");
store.commit("user/setUserInfo", form.value);
router.push("/");
} else {
Toast.fail("更新失敗");
}
};
</script>
<style lang="less" scoped>
@ -481,7 +608,7 @@ export default {
.cropper {
height: 300px;
// width: 300px;
background: #DDD;
background: #ddd;
}
.cropper-section {
@ -493,7 +620,7 @@ export default {
height: 350px;
width: 100%;
max-width: 500px;
background: #DDD;
background: #ddd;
z-index: 8888;
.crop-area {
@ -506,7 +633,6 @@ export default {
background-color: #666;
text-align: center;
}
}
.act-btn {
@ -544,19 +670,19 @@ export default {
}
}
.conten-box{
.conten-box {
width: 100%;
.heading{
.heading-left{
.heading {
.heading-left {
width: 100%;
.title{
.title {
font-weight: 700;
margin-right: 10px;
}
}
.heading-right{
.heading-right {
width: 70px;
}
}
}
</style>
</style>

15948
yarn.lock

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save