fix: 修复SVG颜色异常问题

environments/test/deployments/1
向文可 4 years ago
parent ada5fdcc31
commit 9caaf470ef

@ -53,7 +53,7 @@
"vite": "^2.8.0", "vite": "^2.8.0",
"vite-plugin-remove-console": "^0.0.6", "vite-plugin-remove-console": "^0.0.6",
"vite-plugin-style-import": "^2.0.0", "vite-plugin-style-import": "^2.0.0",
"vite-plugin-svg-icons": "^2.0.1" "vite-svg-loader": "^3.1.2"
}, },
"lint-staged": { "lint-staged": {
"src/**/*.{jsx,tsx,ts,js,vue}": [ "src/**/*.{jsx,tsx,ts,js,vue}": [

@ -1,17 +1,16 @@
<template> <template>
<template v-if="name"> <template v-if="name">
<svg v-if="svg" aria-hidden="true" class="x-icon"> <ElIcon v-if="isElement" class="x-icon">
<use :fill="color" :href="symbolId" />
</svg>
<i v-else-if="isRemix" class="x-icon" :class="'x-icon-' + name" v-bind="{ ...$props, ...$attrs }"></i>
<ElIcon v-else class="x-icon">
<component :is="icons[name]" /> <component :is="icons[name]" />
</ElIcon> </ElIcon>
<i v-else-if="isRemix" class="x-icon" :class="'x-icon-' + name" v-bind="{ ...$props, ...$attrs }"></i>
<component :is="svgs[name]" v-else class="x-icon" />
</template> </template>
</template> </template>
<script setup> <script setup>
import * as icons from '@element-plus/icons'; import { icons, remix, svgs } from '@/icons';
import { ElIcon } from 'element-plus/es/components/icon/index'; import { ElIcon } from 'element-plus/es/components/icon/index';
const props = defineProps({ const props = defineProps({
// //
name: { name: {
@ -34,13 +33,12 @@
default: 'inherit', default: 'inherit',
}, },
}); });
// SVG
const symbolId = computed(() => `#icon-${props.name}`);
// //
const size = computed(() => (Number.isNaN(new Number(props.size).valueOf()) ? props.size : props.size + 'px')); const size = computed(() => (Number.isNaN(new Number(props.size).valueOf()) ? props.size : props.size + 'px'));
const color = computed(() => props.color); const color = computed(() => props.color);
// remixelement-plus //
const isRemix = computed(() => !Object.keys(icons).includes(props.name)); const isElement = computed(() => !props.svg && Object.keys(icons).includes(props.name));
const isRemix = computed(() => !props.svg && remix.includes(props.name));
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@ -53,5 +51,9 @@
width: v-bind(size); width: v-bind(size);
height: v-bind(size); height: v-bind(size);
fill: v-bind(color); fill: v-bind(color);
:deep(image) {
width: 100%;
height: 100%;
}
} }
</style> </style>

@ -1,2 +1,10 @@
import 'virtual:svg-icons-register';
import '@/icons/remixicon.less'; import '@/icons/remixicon.less';
import * as icons from '@element-plus/icons';
import remix from './index.json';
const svgs = Object.fromEntries(
Object.entries(import.meta.globEager('./svg/*.svg')).map((entry) => [
entry[0].split('/').pop().split('.').reverse().slice(1).reverse().join('.'),
entry[1].default,
])
);
export { svgs, icons, remix };

@ -1,12 +1,13 @@
<template> <template>
<div class="layout-logo"> <div class="layout-logo">
<el-icon color="#fff" name="logo" :size="size" svg /> <el-icon :color="color" name="logo" :size="size" svg />
</div> </div>
</template> </template>
<script setup> <script setup>
import variables from '@/styles/globalVariables.module.less'; import variables from '@/styles/globalVariables.module.less';
const size = variables.layoutLogoSize; const size = computed(() => variables.layoutLogoSize);
const color = computed(() => variables.layoutLogoColor);
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@ -20,7 +21,7 @@
.x-icon { .x-icon {
border-radius: @layout-border-radius-large; border-radius: @layout-border-radius-large;
padding: @layout-space-small; padding: @layout-space-small;
background: linear-gradient(180deg, #77b4f6 2%, #4481ff 100%); background: @layout-logo-bg;
} }
} }
</style> </style>

@ -59,6 +59,10 @@
@layout-header-bgc: @color-white; @layout-header-bgc: @color-white;
@layout-header-fc: @color-black; @layout-header-fc: @color-black;
@layout-logo-size: calc(@layout-header-height * 0.72);
@layout-logo-color: @color-white;
@layout-logo-bg: linear-gradient(180deg, #77b4f6 2%, #4481ff 100%);
@layout-tabs-height: 40px; @layout-tabs-height: 40px;
@layout-footer-height: @layout-h1; @layout-footer-height: @layout-h1;
@ -71,5 +75,6 @@
:export { :export {
layoutAsideWidth: @layout-aside-width; layoutAsideWidth: @layout-aside-width;
layoutLogoSize: calc(@layout-header-height * 0.72); layoutLogoSize: @layout-logo-size;
layoutLogoColor: @layout-logo-color;
} }

@ -0,0 +1,115 @@
<template>
<div class="form-container">
<el-form
ref="refsForm"
v-loading="loading"
class="form-content"
:disabled="route.name === 'UserDetail'"
label-width="100px"
:model="form"
:rules="rules"
>
<el-form-item label="用户名" prop="username">
<el-input v-model="form.username" />
</el-form-item>
<el-form-item label="昵称" prop="nickname">
<el-input v-model="form.nickname" />
</el-form-item>
<el-form-item label="性别" prop="sex">
<el-radio-group v-model="form.sex" :opts="opts.sex" />
</el-form-item>
<el-form-item label="头像" prop="avatar">
<el-upload-image v-model="form.avatar" :disabled="route.name === 'UserDetail'" />
</el-form-item>
<el-form-item label="状态" prop="enabled">
<el-switch
v-model="form.enabled"
active-text="启用"
:active-value="true"
inactive-text="禁用"
:inactive-value="false"
/>
</el-form-item>
</el-form>
<div class="form-footer">
<template v-if="route.name !== 'UserDetail'">
<el-button @click="handleCancel"></el-button>
<el-button :disabled="loading" :loading="submitting" type="primary" @click="handleSave"></el-button>
</template>
<el-button v-else @click="handleClose"></el-button>
</div>
</div>
</template>
<script setup>
/* 全局 */
const store = useStore();
const route = useRoute();
const router = useRouter();
const { proxy } = getCurrentInstance();
/* 表单 */
const loading = ref(false);
const submitting = ref(false);
const refsForm = ref(null);
const form = reactive({
username: null,
nickname: null,
sex: 0,
avatar: null,
enabled: true,
});
const rules = reactive({
username: [{ required: true, message: '用户名不能为空' }],
nickname: [{ required: true, message: '昵称不能为空' }],
sex: [{ required: true, message: '性别不能为空' }],
avatar: [{ required: true, message: '头像不能为空' }],
enabled: [{ required: true, message: '状态不能为空' }],
});
const opts = computed(() => store.state.user.opts);
if (!unref(opts).init) {
store.dispatch('user/load');
}
/* 详情 */
watch(
() => [route.name, route.params.id],
async (value) => {
// watch
if (['UpdateUser', 'UserDetail'].includes(value[0]) && value[1]) {
loading.value = true;
let res = await store.dispatch('user/detail', +value[1]);
if (res) {
Object.assign(form, res);
}
loading.value = false;
}
},
{ immediate: true }
);
/* 交互 */
const handleSave = async () => {
submitting.value = true;
try {
await unref(refsForm).validate();
let res = await store.dispatch('user/save', unref(form));
if (res) {
handleClose();
}
} catch (e) {
console.info('取消保存', e);
}
submitting.value = false;
};
const handleCancel = async () => {
try {
await proxy.$confirm('确定要放弃未保存的数据继续离开吗?', '数据未保存');
handleClose();
} catch (e) {
console.info('取消关闭', e);
}
};
const handleClose = () => {
router.push({ name: 'UserManagement' });
};
</script>
<style lang="less" scoped></style>

@ -1,7 +1,169 @@
<template> <template>
<div>权限列表</div> <TableList
v-loading="loading"
:code="code"
:config="config"
:data="list"
:reset="handleReset"
title="用户"
:total="total"
@create="handleCreate"
@remove="handleRemove"
@search="handleSearch"
>
<template #search>
<el-form inline>
<el-form-item label="用户名" prop="username">
<el-input v-model="state.condition.username" />
</el-form-item>
</el-form>
</template>
</TableList>
</template> </template>
<script setup></script> <script setup lang="jsx">
const router = useRouter();
const store = useStore();
const loading = ref(false);
const code = computed(() => store.state.user.code);
const list = computed(() => store.state.user.list);
const total = computed(() => store.state.user.total);
const opts = computed(() => store.state.user.opts);
const state = reactive({
condition: {
username: null,
},
});
watch(
() => state.condition,
(value) => {
store.commit('user/setCondition', _.cloneDeep(value));
},
{ immediate: true, deep: true }
);
const handleReset = () => {
//
return new Promise((resolve) => {
setTimeout(() => {
state.condition = {
username: null,
};
resolve();
}, 1000);
});
};
const handleSearch = async () => {
loading.value = true;
await store.dispatch('user/search');
loading.value = false;
};
const handleCreate = () => {
router.push({ name: 'CreateUser' });
};
const handleUpdate = (row) => {
router.push({ name: 'UpdateUser', params: { id: row.id } });
};
const handleRemove = async (rows) => {
store.dispatch(
'user/remove',
rows.map((item) => item.id)
);
};
const handleDetail = (row) => {
router.push({ name: 'UserDetail', params: { id: row.id } });
};
const handleEnabled = (row, enabled) => {
console.info((enabled ? 'enabled ' : 'disabled ') + row.id);
};
const config = reactive({
//
setting: false,
// ElTable
table: {},
//
page: { sizes: [20, 100] },
//
columns: [
{
type: 'selection',
fixed: 'left',
width: 60,
},
{
label: '用户名',
prop: 'username',
minWidth: 160,
fixed: 'left',
},
{
label: '昵称',
prop: 'nickname',
minWidth: 160,
},
{
label: '性别',
slots: {
default: ({ row }) => unref(opts).sex.find((item) => item.value === row.sex)?.label,
},
width: 100,
},
{
label: '头像',
slots: {
default: ({ row }) => <ElImage src={row.avatar} alt="用户头像" />,
},
width: 100,
},
{
label: '登录时间',
slots: {
default: ({ row }) => dayjs(row.loginTime).format('YYYY-MM-DD HH:mm:ss'),
},
width: 180,
},
{
label: '状态',
slots: {
default: ({ row }) => (
<ElSwitch
modelValue={row.enabled}
active-text="启用"
inactive-text="禁用"
active-value={true}
inactive-value={false}
onInput={(e) => handleEnabled(row, e)}
/>
),
},
width: 160,
},
{
label: '操作',
fixed: 'right',
slots: {
default: ({ row }) => (
<div>
<ElButton type="text" onClick={() => handleUpdate(row)}>
编辑
</ElButton>
<ElButton type="text" onClick={() => handleRemove([row])}>
删除
</ElButton>
<ElDropdown
opts={[
{
label: '详情',
onClick: () => handleDetail(row),
},
]}
/>
</div>
),
},
width: 200,
},
],
});
</script>
<style lang="less" scoped></style> <style lang="less" scoped></style>

@ -1,16 +1,15 @@
import { resolve } from 'path'; import eslintPlugin from '@nabla/vite-plugin-eslint';
import globalStyle from '@originjs/vite-plugin-global-style';
import legacy from '@vitejs/plugin-legacy';
import vue from '@vitejs/plugin-vue'; import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx'; import vueJsx from '@vitejs/plugin-vue-jsx';
import { resolve } from 'path';
import AutoImport from 'unplugin-auto-import/vite'; import AutoImport from 'unplugin-auto-import/vite';
import Components from 'unplugin-vue-components/vite';
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'; import { ElementPlusResolver } from 'unplugin-vue-components/resolvers';
import { createStyleImportPlugin, ElementPlusResolve as ElementPlusStyleResolve } from 'vite-plugin-style-import'; import Components from 'unplugin-vue-components/vite';
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons';
import globalStyle from '@originjs/vite-plugin-global-style';
import removeConsole from 'vite-plugin-remove-console'; import removeConsole from 'vite-plugin-remove-console';
import legacy from '@vitejs/plugin-legacy'; import { createStyleImportPlugin, ElementPlusResolve as ElementPlusStyleResolve } from 'vite-plugin-style-import';
import eslintPlugin from '@nabla/vite-plugin-eslint'; import svgLoader from 'vite-svg-loader';
export default (configEnv) => { export default (configEnv) => {
console.info('command', configEnv.command); console.info('command', configEnv.command);
@ -47,10 +46,7 @@ export default (configEnv) => {
vueJsx({ vueJsx({
transformOn: true, transformOn: true,
}), }),
createSvgIconsPlugin({ svgLoader(),
iconDirs: [resolve(process.cwd(), 'src/icons/svg')],
symbolId: 'icon-[dir]-[name]',
}),
createStyleImportPlugin({ createStyleImportPlugin({
include: ['**/*.js', '**/*.ts', '**/*.tsx', '**/*.jsx', '**/*.vue'], include: ['**/*.js', '**/*.ts', '**/*.tsx', '**/*.jsx', '**/*.vue'],
resolves: [ElementPlusStyleResolve()], resolves: [ElementPlusStyleResolve()],

Loading…
Cancel
Save