'admin-21.06.29:更新最新依赖、各项优化,请查看CHANGELOG.md更新文件'

This commit is contained in:
lyt 2021-06-29 17:20:40 +08:00
parent 92904ffef3
commit b2fd7d6010
22 changed files with 445 additions and 228 deletions

View File

@ -2,6 +2,17 @@
🎉🎉🔥 `vue-next-admin` 基于 vue3.x 、Typescript、vite、Element plus 等适配手机、平板、pc 的后台开源免费模板库vue2.x 请切换 vue-prev-admin 分支)
## 1.0.8
`2021.06.29`
- 🌟 更新 依赖更新最新版本
- 🎉 新增 表单中英文切换演示
- 🎯 优化 登录页查看密码 icon 图标
- 🎯 优化 图标选择器
- 🎯 优化 拖动指令
- 🐞 修复 form 表单在页面小于 576px 时的排版问题
## 1.0.7
`2021.06.24`

View File

@ -1,6 +1,6 @@
{
"name": "vue-next-admin",
"version": "1.0.7",
"version": "1.0.8",
"scripts": {
"dev": "vite",
"build": "vite build",
@ -13,7 +13,7 @@
"cropperjs": "^1.5.12",
"echarts": "^5.1.2",
"echarts-wordcloud": "^2.0.0",
"element-plus": "^1.0.2-beta.51",
"element-plus": "^1.0.2-beta.53",
"mitt": "^3.0.0",
"nprogress": "^0.2.0",
"print-js": "^1.6.0",
@ -32,17 +32,17 @@
"devDependencies": {
"@types/axios": "^0.14.0",
"@types/clipboard": "^2.0.1",
"@types/node": "^15.12.4",
"@types/node": "^15.12.5",
"@types/nprogress": "^0.2.0",
"@types/sortablejs": "^1.10.6",
"@typescript-eslint/eslint-plugin": "^4.28.0",
"@typescript-eslint/parser": "^4.28.0",
"@vitejs/plugin-vue": "^1.2.3",
"@typescript-eslint/eslint-plugin": "^4.28.1",
"@typescript-eslint/parser": "^4.28.1",
"@vitejs/plugin-vue": "^1.2.4",
"@vue/compiler-sfc": "^3.1.2",
"dotenv": "^10.0.0",
"eslint": "^7.29.0",
"eslint-plugin-vue": "^7.11.1",
"prettier": "^2.3.1",
"eslint-plugin-vue": "^7.12.1",
"prettier": "^2.3.2",
"sass": "^1.35.1",
"sass-loader": "^12.1.0",
"typescript": "^4.3.4",

View File

@ -1,35 +1,26 @@
<template>
<div class="icon-selector">
<el-popover :placement="placement" :width="fontIconWidth" v-model:visible="fontIconVisible" popper-class="icon-selector-popper">
<el-popover placement="bottom" :width="fontIconWidth" v-model:visible="fontIconVisible" popper-class="icon-selector-popper">
<template #reference>
<el-input
v-model="fontIcon"
placeholder="请点击选择图标"
clearable
size="small"
v-model="fontIconSearch"
:placeholder="placeholder"
:clearable="clearable"
:disabled="disabled"
:size="size"
ref="inputWidthRef"
:prefix-icon="fontIconPrefix"
@clear="onClearFontIcon"
></el-input>
>
<template #prepend>
<i :class="fontIconPrefix === '' ? prepend : fontIconPrefix" class="font14"></i>
</template>
</el-input>
</template>
<transition name="el-zoom-in-top">
<div class="icon-selector-warp" v-show="fontIconVisible">
<div class="icon-selector-warp-title">请选择一个图标</div>
<div v-if="isAllOn" class="icon-selector-all">
<el-input v-model="fontIconSearch" placeholder="请输入内容进行搜索" size="small"></el-input>
<div class="icon-selector-all-tabs">
<div
class="icon-selector-all-tabs-item"
v-for="(v, k) in fontIconTabsList"
:key="k"
@click="onFontIconTabsClick(v, k)"
:class="{ 'icon-selector-all-tabs-active': fontIconTabsIndex === k }"
>
<div class="label">{{ v.label }}</div>
</div>
</div>
</div>
<div class="icon-selector-warp-title">{{ title }}</div>
<div class="icon-selector-warp-row">
<el-scrollbar>
<el-row :gutter="10">
<el-col
:xs="4"
@ -51,7 +42,8 @@
</div>
</el-col>
</el-row>
<el-empty :image-size="100" v-if="fontIconSheetsFilterList.length <= 0"></el-empty>
<el-empty :image-size="100" v-if="fontIconSheetsFilterList.length <= 0" :description="emptyDescription"></el-empty>
</el-scrollbar>
</div>
</div>
</transition>
@ -65,21 +57,50 @@ import initIconfont from '/@/utils/getStyleSheets';
export default {
name: 'iconSelector',
props: {
//
isAllOn: {
//
prepend: {
type: String,
default: () => 'el-icon-thumb',
},
//
placeholder: {
type: String,
default: () => '请输入内容搜索图标或者选择图标',
},
//
size: {
type: String,
default: () => 'small',
},
//
title: {
type: String,
default: () => '请选择图标',
},
// icon
type: {
type: String,
default: () => 'ele',
},
//
disabled: {
type: Boolean,
default: () => false,
},
//
placement: {
//
clearable: {
type: Boolean,
default: () => true,
},
//
emptyDescription: {
type: String,
default: () => 'bottom',
default: () => '无相关图标',
},
},
setup(props, { emit }) {
const inputWidthRef = ref();
const state: any = reactive({
fontIcon: '',
fontIconPrefix: '',
fontIconVisible: false,
fontIconWidth: 0,
@ -87,11 +108,7 @@ export default {
fontIconSearch: '',
fontIconTabsIndex: 0,
fontIconTabsIcon: 'iconfont ali',
fontIconTabsList: [{ label: 'iconfont' }, { label: 'element' }, { label: 'awesome' }],
fontIconSheetsList: [],
fontIconSheetsListAli: [],
fontIconSheetsListEle: [],
fontIconSheetsListAwe: [],
});
//
const fontIconSheetsFilterList = computed(() => {
@ -115,42 +132,40 @@ export default {
};
//
const initFontIconData = () => {
if (props.type === 'ali') {
initIconfont.ali().then((res: any) => {
state.fontIconTabsIcon = 'iconfont ali';
state.fontIconTabsIndex = 0;
state.fontIconSheetsList = res;
state.fontIconSheetsListAli = res;
});
} else if (props.type === 'ele') {
initIconfont.ele().then((res: any) => {
state.fontIconSheetsListEle = res;
state.fontIconTabsIcon = 'ele';
state.fontIconTabsIndex = 1;
state.fontIconSheetsList = res;
});
} else if (props.type === 'awe') {
initIconfont.awe().then((res: any) => {
state.fontIconSheetsListAwe = res;
state.fontIconTabsIcon = 'fa awe';
state.fontIconTabsIndex = 2;
state.fontIconSheetsList = res;
});
}
};
//
// icon
const onColClick = (v: any, k: number) => {
state.fontIconIndex = k;
state.fontIcon = v;
state.fontIconVisible = false;
if (state.fontIconTabsIndex === 0) state.fontIconPrefix = `iconfont ali ${v}`;
else if (state.fontIconTabsIndex === 1) state.fontIconPrefix = `ele ${v}`;
else if (state.fontIconTabsIndex === 2) state.fontIconPrefix = `fa awe ${v}`;
emit('get', state.fontIconPrefix);
};
// input
// icon
const onClearFontIcon = () => {
state.fontIconIndex = '';
state.fontIconPrefix = '';
emit('get', state.fontIconPrefix);
};
// tabs
const onFontIconTabsClick = (v: any, k: number) => {
state.fontIconTabsIndex = k;
if (v.label === 'iconfont') state.fontIconSheetsList = state.fontIconSheetsListAli;
else if (v.label === 'element') state.fontIconSheetsList = state.fontIconSheetsListEle;
else if (v.label === 'awesome') state.fontIconSheetsList = state.fontIconSheetsListAwe;
if (k === 0) state.fontIconTabsIcon = `iconfont ali`;
else if (k === 1) state.fontIconTabsIcon = `ele`;
else if (k === 2) state.fontIconTabsIcon = `fa awe`;
emit('clear', state.fontIconPrefix);
};
//
onMounted(() => {
@ -163,7 +178,6 @@ export default {
fontIconSheetsFilterList,
onColClick,
onClearFontIcon,
onFontIconTabsClick,
...toRefs(state),
};
},

View File

@ -14,6 +14,9 @@ import pagesHomeZhtw from '/@/i18n/pages/home/zh-tw';
import pagesLoginZhcn from '/@/i18n/pages/login/zh-cn';
import pagesLoginEn from '/@/i18n/pages/login/en';
import pagesLoginZhtw from '/@/i18n/pages/login/zh-tw';
import pagesFormI18nZhcn from '/@/i18n/pages/formI18n/zh-cn';
import pagesFormI18nEn from '/@/i18n/pages/formI18n/en';
import pagesFormI18nZhtw from '/@/i18n/pages/formI18n/zh-tw';
// 定义语言国际化内容
/**
@ -28,6 +31,7 @@ const messages = {
...nextZhcn,
...pagesHomeZhcn,
...pagesLoginZhcn,
...pagesFormI18nZhcn,
},
},
[enLocale.name]: {
@ -36,6 +40,7 @@ const messages = {
...nextEn,
...pagesHomeEn,
...pagesLoginEn,
...pagesFormI18nEn,
},
},
[zhtwLocale.name]: {
@ -44,6 +49,7 @@ const messages = {
...nextZhtw,
...pagesHomeZhtw,
...pagesLoginZhtw,
...pagesFormI18nZhtw,
},
},
};

View File

@ -42,6 +42,7 @@ export default {
pagesAwesome: 'awesome icon',
pagesCityLinkage: 'CityLinkage',
pagesFormAdapt: 'FormAdapt',
pagesFormI18n: 'FormI18n',
pagesListAdapt: 'ListAdapt',
pagesWaterfall: 'Waterfall',
pagesSteps: 'Steps',

View File

@ -42,6 +42,7 @@ export default {
pagesAwesome: 'awesome 字体图标',
pagesCityLinkage: '城市多级联动',
pagesFormAdapt: '表单自适应',
pagesFormI18n: '表单国际化',
pagesListAdapt: '列表自适应',
pagesWaterfall: '瀑布屏',
pagesSteps: '步骤条',

View File

@ -42,6 +42,7 @@ export default {
pagesAwesome: 'awesome 字體圖標',
pagesCityLinkage: '都市多級聯動',
pagesFormAdapt: '表單自我調整',
pagesFormI18n: '表單國際化',
pagesListAdapt: '清單自我調整',
pagesWaterfall: '瀑布屏',
pagesSteps: '步驟條',

View File

@ -0,0 +1,13 @@
// 定义内容
export default {
formI18nLabel: {
name: 'name',
email: 'email',
autograph: 'autograph',
},
formI18nPlaceholder: {
name: 'Please enter your name',
email: 'Please enter the users Department',
autograph: 'Please enter the login account name',
},
};

View File

@ -0,0 +1,13 @@
// 定义内容
export default {
formI18nLabel: {
name: '姓名',
email: '用户归属部门',
autograph: '登陆账户名',
},
formI18nPlaceholder: {
name: '请输入姓名',
email: '请输入用户归属部门',
autograph: '请输入登陆账户名',
},
};

View File

@ -0,0 +1,13 @@
// 定义内容
export default {
formI18nLabel: {
name: '姓名',
email: '用戶歸屬部門',
autograph: '登入帳戶名',
},
formI18nPlaceholder: {
name: '請輸入姓名',
email: '請輸入用戶歸屬部門',
autograph: '請輸入登入帳戶名',
},
};

View File

@ -665,6 +665,21 @@ export const dynamicRoutes: Array<RouteRecordRaw> = [
icon: 'iconfont icon-biaodan',
},
},
{
path: '/pages/formI18n',
name: 'pagesFormI18n',
component: () => import('/@/views/pages/formI18n/index.vue'),
meta: {
title: 'message.router.pagesFormI18n',
isLink: '',
isHide: false,
isKeepAlive: true,
isAffix: false,
isIframe: false,
auth: ['admin', 'test'],
icon: 'iconfont icon-diqiu',
},
},
{
path: '/pages/listAdapt',
name: 'pagesListAdapt',

View File

@ -940,7 +940,7 @@
}
}
.el-dialog__body {
max-height: 70vh !important;
max-height: calc(90vh - 111px) !important;
overflow-y: auto;
overflow-x: hidden;
}

View File

@ -3,16 +3,23 @@
.icon-selector-popper {
padding: 0 !important;
.icon-selector-warp {
height: 300px;
overflow: hidden;
.icon-selector-warp-title {
height: 40px;
line-height: 40px;
padding: 0 15px;
}
.icon-selector-warp-row {
max-height: 260px;
overflow-y: auto;
padding: 15px 15px 5px;
height: 260px;
overflow: hidden;
border-top: 1px solid #ebeef5;
.el-row {
padding: 15px;
}
.el-scrollbar__bar.is-horizontal {
display: none;
}
.ele-col:nth-last-child(1),
.ele-col:nth-last-child(2) {
display: none;
@ -26,28 +33,26 @@
padding: 10px;
border-radius: 5px;
margin-bottom: 10px;
transition: all 0.3s ease;
.icon-selector-warp-item-value {
transition: all 0.3s ease;
i {
font-size: 20px;
color: #606266;
}
}
&:hover {
border: 1px solid var(--color-primary);
cursor: pointer;
transition: all 0.3s ease;
background-color: var(--color-primary-light-9);
border: 1px solid var(--color-primary-light-6);
.icon-selector-warp-item-value {
i {
color: var(--color-primary);
transition: all 0.3s ease;
}
}
}
}
.icon-selector-active {
border: 1px solid var(--color-primary);
background-color: var(--color-primary-light-9);
border: 1px solid var(--color-primary-light-6);
.icon-selector-warp-item-value {
i {
color: var(--color-primary);
@ -55,33 +60,5 @@
}
}
}
.icon-selector-all {
.el-input {
padding: 0 15px;
margin-bottom: 10px;
}
&-tabs {
display: flex;
height: 30px;
line-height: 30px;
padding: 0 15px;
margin-bottom: 5px;
&-item {
flex: 1;
text-align: center;
cursor: pointer;
&:hover {
color: var(--color-primary);
}
}
&-active {
background: var(--color-primary);
border-radius: 5px;
.label {
color: #ffffff;
}
}
}
}
}
}

View File

@ -10,4 +10,7 @@
.el-form-item__content {
margin-left: 0 !important;
}
.el-form-item {
display: unset !important;
}
}

View File

@ -64,21 +64,16 @@ export function dragDirective(app: App) {
app.directive('drag', {
mounted(el, binding) {
if (!binding.value) return false;
const dragDom = document.querySelector(binding.value[0]) as HTMLElement;
const dragHeader = document.querySelector(binding.value[1]) as HTMLElement;
dragHeader.onmouseover = () => (dragHeader.style.cursor = `move`);
/**
* pc端
* onmousedown
* onmousemove
* onmouseup
*/
dragHeader.onmousedown = (e) => {
function down(e: any, type: string) {
// 鼠标按下,计算当前元素距离可视区的距离
const disX = e.clientX - dragHeader.offsetLeft;
const disY = e.clientY - dragHeader.offsetTop;
const disX = type === 'pc' ? e.clientX - dragHeader.offsetLeft : e.touches[0].clientX - dragHeader.offsetLeft;
const disY = type === 'pc' ? e.clientY - dragHeader.offsetTop : e.touches[0].clientY - dragHeader.offsetTop;
// body当前宽度
const screenWidth = document.body.clientWidth;
@ -109,10 +104,24 @@ export function dragDirective(app: App) {
styT = +styT.replace(/\px/g, '');
}
document.onmousemove = (e) => {
return {
disX,
disY,
minDragDomLeft,
maxDragDomLeft,
minDragDomTop,
maxDragDomTop,
styL,
styT,
};
}
function move(e: any, type: string, obj: any) {
let { disX, disY, minDragDomLeft, maxDragDomLeft, minDragDomTop, maxDragDomTop, styL, styT } = obj;
// 通过事件委托,计算移动的距离
let left = e.clientX - disX;
let top = e.clientY - disY;
let left = type === 'pc' ? e.clientX - disX : e.touches[0].clientX - disX;
let top = type === 'pc' ? e.clientY - disY : e.touches[0].clientY - disY;
// 边界处理
if (-left > minDragDomLeft) {
@ -129,8 +138,19 @@ export function dragDirective(app: App) {
// 移动当前元素
dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`;
};
}
/**
* pc端
* onmousedown
* onmousemove
* onmouseup
*/
dragHeader.onmousedown = (e) => {
const obj = down(e, 'pc');
document.onmousemove = (e) => {
move(e, 'pc', obj);
};
document.onmouseup = () => {
document.onmousemove = null;
document.onmouseup = null;
@ -138,67 +158,16 @@ export function dragDirective(app: App) {
};
/**
*
*
* ontouchstart ontouchstart
* ontouchmove ontouchmove
* ontouchend ontouchend
*/
dragHeader.ontouchstart = (e) => {
// 鼠标按下,计算当前元素距离可视区的距离
const disX = e.touches[0].clientX - dragHeader.offsetLeft;
const disY = e.touches[0].clientY - dragHeader.offsetTop;
// body当前宽度
const screenWidth = document.body.clientWidth;
// 可见区域高度(应为body高度可某些环境下无法获取)
const screenHeight = document.documentElement.clientHeight;
// 对话框宽度
const dragDomWidth = dragDom.offsetWidth;
// 对话框高度
const dragDomheight = dragDom.offsetHeight;
const minDragDomLeft = dragDom.offsetLeft;
const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth;
const minDragDomTop = dragDom.offsetTop;
const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight;
// 获取到的值带px 正则匹配替换
let styL: any = getComputedStyle(dragDom).left;
let styT: any = getComputedStyle(dragDom).top;
// 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
if (styL.includes('%')) {
styL = +document.body.clientWidth * (+styL.replace(/\%/g, '') / 100);
styT = +document.body.clientHeight * (+styT.replace(/\%/g, '') / 100);
} else {
styL = +styL.replace(/\px/g, '');
styT = +styT.replace(/\px/g, '');
}
const obj = down(e, 'app');
document.ontouchmove = (e) => {
// 通过事件委托,计算移动的距离
let left = e.touches[0].clientX - disX;
let top = e.touches[0].clientY - disY;
// 边界处理
if (-left > minDragDomLeft) {
left = -minDragDomLeft;
} else if (left > maxDragDomLeft) {
left = maxDragDomLeft;
}
if (-top > minDragDomTop) {
top = -minDragDomTop;
} else if (top > maxDragDomTop) {
top = maxDragDomTop;
}
// 移动当前元素
dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`;
move(e, 'app', obj);
};
document.ontouchend = () => {
document.ontouchmove = null;
document.ontouchend = null;

View File

@ -1,6 +1,6 @@
// 字体图标 url
const cssCdnUrlList: Array<string> = [
'//at.alicdn.com/t/font_2298093_ysc3z187xhh.css',
'//at.alicdn.com/t/font_2298093_wl7t9plo8fs.css',
'//netdna.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css',
];
// 第三方 js url

View File

@ -1,30 +1,124 @@
<template>
<div class="selector-container">
<el-card shadow="hover" header="1、图标选择器(宽度自动):简单版本">
<IconSelector @get="ongetCurrentIcon" />
<el-card shadow="hover" header="图标选择器(宽度自动):简单版本">
<IconSelector @get="onGetIcon" @clear="onClearIcon" />
</el-card>
<el-card shadow="hover" header="2、图标选择器(宽度自动):高级版本" class="mt15">
<IconSelector @get="ongetCurrentIcon" :isAllOn="true" />
<el-card shadow="hover" header="图标选择器(宽度自动):参数" class="mt15">
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="a1" label="参数"> </el-table-column>
<el-table-column prop="a2" label="说明"> </el-table-column>
<el-table-column prop="a3" label="类型"> </el-table-column>
<el-table-column prop="a4" label="可选值"> </el-table-column>
<el-table-column prop="a5" label="默认值"> </el-table-column>
</el-table>
</el-card>
<el-card shadow="hover" header="图标选择器(宽度自动):事件" class="mt15">
<el-table :data="tableData1" style="width: 100%">
<el-table-column prop="a1" label="事件名称"> </el-table-column>
<el-table-column prop="a2" label="说明"> </el-table-column>
<el-table-column prop="a3" label="类型"> </el-table-column>
<el-table-column prop="a4" label="回调参数"> </el-table-column>
</el-table>
</el-card>
</div>
</template>
<script lang="ts">
import { toRefs, reactive } from 'vue';
import { toRefs, reactive, defineComponent } from 'vue';
import IconSelector from '/@/components/iconSelector/index.vue';
export default {
export default defineComponent({
name: 'funSelector',
components: { IconSelector },
setup() {
const state = reactive({});
const state = reactive({
tableData: [
{
a1: 'prepend',
a2: '输入框前置内容,只能字体图标',
a3: 'string',
a4: '',
a5: 'el-icon-thumb',
},
{
a1: 'placeholder',
a2: '输入框占位文本',
a3: 'string',
a4: '',
a5: '请输入内容搜索图标或者选择图标',
},
{
a1: 'size',
a2: '尺寸',
a3: 'string',
a4: 'medium / small / mini',
a5: 'small',
},
{
a1: 'title',
a2: '弹窗标题',
a3: 'string',
a4: '',
a5: '请选择图标',
},
{
a1: 'type',
a2: 'icon 图标类型',
a3: 'string',
a4: 'ali / ele / awe',
a5: 'ele',
},
{
a1: 'disabled',
a2: '禁用',
a3: 'boolean',
a4: 'true',
a5: 'false',
},
{
a1: 'clearable',
a2: '是否可清空',
a3: 'boolean',
a4: 'false',
a5: 'true',
},
{
a1: 'emptyDescription',
a2: '自定义空状态描述文字',
a3: 'String',
a4: '',
a5: '无相关图标',
},
],
tableData1: [
{
a1: 'get',
a2: '获取当前点击的 icon 图标',
a3: 'function',
a4: '(icon: string)',
},
{
a1: 'clear',
a2: '清空当前点击的 icon 图标',
a3: 'function',
a4: '(icon: string)',
},
],
});
// icon
const ongetCurrentIcon = (v: string) => {
console.log(v);
const onGetIcon = (icon: string) => {
console.log(icon);
};
// icon
const onClearIcon = (icon: string) => {
console.log(icon);
};
return {
ongetCurrentIcon,
onGetIcon,
onClearIcon,
...toRefs(state),
};
},
};
});
</script>

View File

@ -1,5 +1,5 @@
<template>
<div>
<div class="fun-tagsview">
<el-card shadow="hover" header="tagsView 非当前页演示">
<el-form :model="formInline" size="small" label-width="40px" class="tags-view-form">
<el-row :gutter="35">
@ -16,7 +16,7 @@
</el-form-item>
</el-col>
<el-col :xs="24" :sm="8" :md="8" :lg="6" :xl="4">
<el-form-item>
<el-form-item class="fun-tagsview-from-item">
<el-button type="primary" @click="onImplementClick" icon="el-icon-thumb">点击执行</el-button>
</el-form-item>
</el-col>
@ -146,3 +146,13 @@ export default {
},
};
</script>
<style scoped lang="scss">
.fun-tagsview {
.fun-tagsview-from-item {
::v-deep(.el-form-item__content) {
margin-left: 0 !important;
}
}
}
</style>

View File

@ -13,13 +13,20 @@
</el-form-item>
<el-form-item>
<el-input
type="password"
:type="isShowPassword ? 'text' : 'password'"
:placeholder="$t('message.account.accountPlaceholder2')"
prefix-icon="el-icon-lock"
v-model="ruleForm.password"
autocomplete="off"
show-password
>
<template #suffix>
<i
class="iconfont el-input__icon login-content-password"
:class="isShowPassword ? 'icon-yincangmima' : 'icon-xianshimima'"
@click="isShowPassword = !isShowPassword"
>
</i>
</template>
</el-input>
</el-form-item>
<el-form-item>
@ -69,6 +76,7 @@ export default defineComponent({
const route = useRoute();
const router = useRouter();
const state = reactive({
isShowPassword: false,
ruleForm: {
userName: 'admin',
password: '123456',
@ -162,6 +170,14 @@ export default defineComponent({
<style scoped lang="scss">
.login-content-form {
margin-top: 20px;
.login-content-password {
display: inline-block;
width: 25px;
cursor: pointer;
&:hover {
color: #909399;
}
}
.login-content-code {
display: flex;
align-items: center;

View File

@ -4,7 +4,7 @@
<el-input
type="text"
:placeholder="$t('message.mobile.placeholder1')"
prefix-icon="el-icon-user"
prefix-icon="iconfont icon-dianhua"
v-model="ruleForm.userName"
clearable
autocomplete="off"
@ -25,7 +25,7 @@
></el-input>
</el-col>
<el-col :span="8">
<el-button>{{ $t('message.mobile.codeText') }}</el-button>
<el-button class="login-content-code">{{ $t('message.mobile.codeText') }}</el-button>
</el-col>
</el-row>
</el-form-item>
@ -58,6 +58,13 @@ export default defineComponent({
<style scoped lang="scss">
.login-content-form {
margin-top: 20px;
::v-deep(.el-input__icon) {
display: inline-block;
}
.login-content-code {
width: 100%;
padding: 0;
}
.login-content-submit {
width: 100%;
letter-spacing: 2px;

View File

@ -8,7 +8,6 @@
:props="{ expandTrigger: 'hover', value: 'code', label: 'name' }"
size="small"
clearable
class="w100"
>
</el-cascader>
</el-card>
@ -43,9 +42,9 @@
</template>
<script lang="ts">
import { toRefs, reactive, onMounted } from 'vue';
import { toRefs, reactive, onMounted, defineComponent } from 'vue';
import threeLevelLinkageJson from '/@/mock/threeLevelLinkage.json';
export default {
export default defineComponent({
name: 'pagesCityLinkage',
setup() {
const state = reactive({
@ -93,5 +92,5 @@ export default {
...toRefs(state),
};
},
};
});
</script>

View File

@ -0,0 +1,54 @@
<template>
<div class="form-i18n-container">
<el-card shadow="hover" header="表单国际化演示(不适用于动态项 form-item)">
<div style="text-align: center; margin-top: 15px">
<el-radio-group v-model="radio" size="small" @change="onRadioChange">
<el-radio-button label="zh-cn">中文简体</el-radio-button>
<el-radio-button label="en">英文</el-radio-button>
<el-radio-button label="zh-tw">中文繁体</el-radio-button>
</el-radio-group>
</div>
<el-form :model="form" size="small" label-width="100px" class="mt35 mb35">
<el-row :gutter="35">
<el-col :xs="24" :sm="12" :md="8" :lg="8" :xl="8" class="mb20">
<el-form-item :label="$t('message.formI18nLabel.name')">
<el-input v-model="form.name" :placeholder="$t('message.formI18nPlaceholder.name')" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="8" :xl="8" class="mb20">
<el-form-item :label="$t('message.formI18nLabel.email')">
<el-input v-model="form.email" :placeholder="$t('message.formI18nPlaceholder.email')" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="8" :xl="8" class="mb20">
<el-form-item :label="$t('message.formI18nLabel.autograph')">
<el-input v-model="form.autograph" :placeholder="$t('message.formI18nPlaceholder.autograph')" clearable></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
</div>
</template>
<script lang="ts">
import { toRefs, reactive, defineComponent, getCurrentInstance } from 'vue';
export default defineComponent({
name: 'pagesFormI18n',
setup() {
const { proxy } = getCurrentInstance() as any;
const state = reactive({
radio: 'zh-cn',
form: {},
});
//
const onRadioChange = () => {
proxy.$i18n.locale = state.radio;
};
return {
onRadioChange,
...toRefs(state),
};
},
});
</script>