feat:eslint + prettier

environments/test/deployments/1
saatana 4 years ago
parent 47e13a9dfb
commit 9eee03bf55

File diff suppressed because one or more lines are too long

@ -5,7 +5,7 @@ module.exports = {
node: true,
browser: true,
},
extends: ['eslint:recommended'],
extends: ['eslint:recommended', 'plugin:vue/vue3-recommended', 'plugin:prettier/recommended', '@vue/prettier'],
parser: 'vue-eslint-parser',
parserOptions: {
ecmaVersion: 'latest',
@ -16,10 +16,106 @@ module.exports = {
},
},
rules: {
'no-undef': 'error',
'no-alert': 'warn',
'no-debugger': 'warn',
'no-undef': 'error',
'no-else-return': 'error',
'no-console': 'off',
'vue/no-v-html': 'off',
'vue/html-self-closing': [
'error',
{
html: {
void: 'any',
normal: 'any',
component: 'always',
},
svg: 'always',
math: 'always',
},
],
'vue/multi-word-component-names': 'off',
'vue/order-in-components': [
'warn',
{
order: [
'el',
'name',
'key',
'parent',
'functional',
['delimiters', 'comments'],
['components', 'directives', 'filters'],
'extends',
'mixins',
['provide', 'inject'],
'ROUTER_GUARDS',
'layout',
'middleware',
'validate',
'scrollToTop',
'transition',
'loading',
'inheritAttrs',
'model',
['props', 'propsData'],
'emits',
'setup',
'fetch',
'asyncData',
'data',
'head',
'computed',
'watch',
'watchQuery',
'LIFECYCLE_HOOKS',
'methods',
['template', 'render'],
'renderError',
],
},
],
'vue/attributes-order': [
'warn',
{
order: [
'DEFINITION',
'LIST_RENDERING',
'CONDITIONALS',
'RENDER_MODIFIERS',
'GLOBAL',
'UNIQUE',
'TWO_WAY_BINDING',
'OTHER_DIRECTIVES',
'OTHER_ATTR',
'EVENTS',
'CONTENT',
],
alphabetical: true, //字母顺序
},
],
// 'prettier/prettier': [
// 'error',
// {
// printWidth: 120,
// tabWidth: 4,
// useTabs: false,
// semi: true,
// singleQuote: true,
// quoteProps: 'as-needed',
// jsxSingleQuote: false,
// trailingComma: 'es5',
// bracketSpacing: true,
// bracketSameLine: false,
// arrowParens: 'always',
// htmlWhitespaceSensitivity: 'ignore',
// vueIndentScriptAndStyle: true,
// endOfLine: 'auto',
// },
// {
// usePrettierrc: true,
// },
// ],
indent: [0, 4],
eqeqeq: [2, 'always'],
semi: [2, 'always'],

@ -1,45 +1,52 @@
{
"name": "msb-shop-admin",
"author": {
"name": "向文可",
"email": "1041367524@qq.com"
},
"private": true,
"version": "0.0.1",
"scripts": {
"dev": "vite",
"build:test": "vite build --mode test",
"build:preview": "vite build --mode preview",
"build:prod": "vite build --mode prod",
"preview": "vite preview"
},
"dependencies": {
"@element-plus/icons": "^0.0.11",
"@vueup/vue-quill": "^1.0.0-beta.8",
"axios": "^0.26.1",
"dayjs": "^1.11.0",
"element-plus": "^2.1.2",
"lodash": "^4.17.21",
"qs": "^6.10.3",
"quill-image-uploader": "^1.2.2",
"sortablejs": "^1.14.0",
"vue": "^3.2.25",
"vue-router": "^4.0.14",
"vuex": "^4.0.2"
},
"devDependencies": {
"@originjs/vite-plugin-global-style": "^1.0.2",
"@types/node": "^17.0.21",
"@vitejs/plugin-legacy": "^1.7.1",
"@vitejs/plugin-vue": "^2.2.0",
"@vitejs/plugin-vue-jsx": "^1.3.8",
"consola": "^2.15.3",
"less": "^4.1.2",
"unplugin-auto-import": "^0.6.4",
"unplugin-vue-components": "^0.18.0",
"vite": "^2.8.0",
"vite-plugin-remove-console": "^0.0.6",
"vite-plugin-style-import": "^2.0.0",
"vite-plugin-svg-icons": "^2.0.1"
}
"name": "msb-shop-admin",
"author": {
"name": "向文可",
"email": "1041367524@qq.com"
},
"private": true,
"version": "0.0.1",
"scripts": {
"dev": "vite",
"build:test": "vite build --mode test",
"build:preview": "vite build --mode preview",
"build:prod": "vite build --mode prod",
"preview": "vite preview",
"lint": "eslint src/**/*.{vue,js,jsx} --fix"
},
"dependencies": {
"@element-plus/icons": "^0.0.11",
"@vueup/vue-quill": "^1.0.0-beta.8",
"axios": "^0.26.1",
"dayjs": "^1.11.0",
"element-plus": "^2.1.2",
"lodash": "^4.17.21",
"qs": "^6.10.3",
"quill-image-uploader": "^1.2.2",
"sortablejs": "^1.14.0",
"vue": "^3.2.25",
"vue-router": "^4.0.14",
"vuex": "^4.0.2"
},
"devDependencies": {
"@nabla/vite-plugin-eslint": "^1.4.0",
"@originjs/vite-plugin-global-style": "^1.0.2",
"@types/node": "^17.0.21",
"@vitejs/plugin-legacy": "^1.7.1",
"@vitejs/plugin-vue": "^2.2.0",
"@vitejs/plugin-vue-jsx": "^1.3.8",
"consola": "^2.15.3",
"eslint": "^8.11.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^8.5.0",
"less": "^4.1.2",
"prettier": "^2.6.0",
"unplugin-auto-import": "^0.6.4",
"unplugin-vue-components": "^0.18.0",
"vite": "^2.8.0",
"vite-plugin-remove-console": "^0.0.6",
"vite-plugin-style-import": "^2.0.0",
"vite-plugin-svg-icons": "^2.0.1"
}
}

@ -1,10 +1,10 @@
<template>
<el-config-provider
:button="config.button"
:locale="config.locale"
:message="config.message"
:size="config.size"
:z-index="config.zIndex"
:button="config.button"
:message="config.message"
>
<router-view />
</el-config-provider>
@ -12,7 +12,6 @@
<script setup>
import zh from 'element-plus/lib/locale/lang/zh-cn';
const route = useRoute();
const config = reactive({
locale: zh,
size: 'default',

@ -34,6 +34,7 @@ let list = [
},
];
export const findUserList = (data) => {
console.info(data);
return mock({ content: list, totalElements: list.length });
};
export const createUser = (data) => {

@ -1,5 +1,5 @@
<template>
<component :is="render"></component>
<component :is="render" />
</template>
<script lang="jsx">
export default defineComponent({
@ -47,17 +47,17 @@
['clean'],
],
imageUploader: {
upload: (file) => {
return new Promise(async (resolve, reject) => {
const formdata = new FormData();
formdata.append('file', file);
const url = await upload(formdata);
if (url) {
resolve(url);
} else {
reject('上传失败');
}
});
upload: async (file) => {
let res = null;
const formdata = new FormData();
formdata.append('file', file);
const url = await upload(formdata);
if (url) {
res = url;
} else {
throw new Error('上传失败');
}
return res;
},
},
},
@ -74,10 +74,10 @@
},
{ deep: true }
);
const handleReady = (e) => {
const handleReady = () => {
unref(editor).setHTML(attrs.modelValue || '');
};
const handleUpdateContent = (value) => {
const handleUpdateContent = () => {
content.value = unref(editor).getHTML();
};

@ -1,7 +1,7 @@
<template>
<template v-if="name">
<svg v-if="svg" class="x-icon" aria-hidden="true">
<use :href="symbolId" :fill="color" />
<svg v-if="svg" aria-hidden="true" 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">

@ -61,12 +61,13 @@
),
...slots,
};
if (props.previewSrcList?.length === 0) {
props.previewSrcList.push(props.src);
let previewSrcList = [...props.previewSrcList];
if (previewSrcList?.length === 0) {
previewSrcList.push(props.src);
}
const width = computed(() => props.width);
const height = computed(() => props.height);
const render = () => <ElImage {...props} {...attrs} v-slots={imageSlots} />;
const render = () => <ElImage {...{ ...props, previewSrcList }} {...attrs} v-slots={imageSlots} />;
</script>
<style lang="less" scoped>

@ -27,10 +27,6 @@
return props.type === 'password';
},
},
showWordLimit: {
type: Boolean,
default: true,
},
rows: {
type: Number,
default: 3,

@ -53,7 +53,8 @@
});
const attrs = useAttrs();
const emits = defineEmits(['update:modelValue']);
props.headers['Authorization'] = 'Bearer ' + store.state.local.token;
let headers = { ...props.headers };
headers['Authorization'] = 'Bearer ' + store.state.local.token;
let imgList = ref([]);
const refsUpload = ref(null);
watch(
@ -136,10 +137,10 @@
)}
</div>
))}
{props.limit != unref(imgList).length ? (
{props.limit !== unref(imgList).length ? (
<ElUpload
ref={refsUpload}
{...props}
{...{ ...props, headers }}
{...attrs}
before-upload={handleBeforeUpload}
on-exceed={handleExceed}

@ -2,9 +2,7 @@
<div class="layout-footer">© 2020 马士兵北京教育科技有限公司</div>
</template>
<script setup>
import Breakcrumb from './breakcrumb.vue';
</script>
<script setup></script>
<style lang="less" scoped>
.layout-footer {

@ -1,6 +1,6 @@
<template>
<div class="layout-logo">
<el-icon name="logo" svg :size="size" color="#fff" />
<el-icon color="#fff" name="logo" :size="size" svg />
</div>
</template>

@ -1,5 +1,5 @@
<template>
<el-scrollbar class="layout-main" ref="refsScrollbar" max-height="100%">
<el-scrollbar ref="refsScrollbar" class="layout-main" max-height="100%">
<RouterView />
</el-scrollbar>
</template>

@ -2,7 +2,7 @@
<div class="layout-menu" :class="{ collapse: collapseMenu }">
<LayoutTitle />
<el-scrollbar>
<el-menu unique-opened :default-active="activeMenu" @select="handleSelect">
<el-menu :default-active="activeMenu" unique-opened @select="handleSelect">
<MenuItem v-for="(item, index) in menuList" :key="index" :menu-item="item" />
</el-menu>
</el-scrollbar>

@ -13,9 +13,7 @@
const opts = reactive([
{
label: '个人中心',
onClick() {
alert('个人中心');
},
onClick() {},
},
{
label: '退出登录',

@ -1,6 +1,6 @@
<template>
<div class="layout-tabs">
<el-tabs :modelValue="activeTab" type="card" class="demo-tabs" @tab-click="handleClick">
<el-tabs class="demo-tabs" :model-value="activeTab" type="card" @tab-click="handleClick">
<el-tab-pane v-for="(item, index) in tabList" :key="index" :name="item.name">
<template #label>
<el-icon class="tab-icon" :name="item.meta.icon" />
@ -15,7 +15,7 @@
</el-tab-pane>
</el-tabs>
<div class="operation">
<el-dropdown trigger="hover" :opts="opts" icon="apps-fill">
<el-dropdown icon="apps-fill" :opts="opts" trigger="hover">
<span></span>
</el-dropdown>
</div>

@ -7,7 +7,6 @@
<script setup>
import config from '@/configs';
const store = useStore();
const activeAsideName = computed(() => store.getters['layout/activeAsideName']);
const collapseMenu = computed(() => store.getters['layout/collapseMenu']);
</script>

@ -36,7 +36,7 @@ const actions = {
],
});
},
detail: async ({ state }, id) => {
detail: async (context, id) => {
let res = await api.getUserDetail(id);
if (!res) {
ElMessage.error('加载详情失败');

@ -6,7 +6,7 @@ const during = (func, name = 'func') => {
} catch (e) {
error = e;
}
const msg = `[debug] exec ${name} during ${Date.now() - time}ms`;
let msg = `[debug] exec ${name} during ${Date.now() - time}ms`;
if (error) {
msg += ' with error';
}

@ -62,12 +62,13 @@ instance.interceptors.request.use(
instance.interceptors.response.use(
(response) => handleResponse(response),
(error) => {
let res = null;
if (!error.response) {
ElMessage.error('服务器无响应');
return null;
} else {
return handleResponse(error.response);
res = handleResponse(error.response);
}
return res;
}
);

@ -13,12 +13,12 @@
<p>{{ list.find((item) => item.id === '1').childList.map((item) => item.id) }}</p>
<ElTable
v-loading="listLoading"
sortable
border
code="parent"
:data="list"
group="test"
:row-class-name="handleRowClassName"
sortable
@row-add="handleRowAdd"
@row-clone="handleRowClone"
@row-remove="handleRowRemove"
@ -28,12 +28,12 @@
<template #default="{ row }">
<ElTable
v-loading="listLoading"
sortable
border
code="child"
:data="row.childList || []"
:group="{ name: 'test', pull: 'clone' }"
:row-class-name="handleRowClassName"
sortable
@row-add="handleChildrenRowAdd"
@row-clone="handleChildrenRowClone"
@row-remove="handleChildrenRowRemove"
@ -67,7 +67,6 @@
</template>
<script>
import { ElMessage } from '@/plugins/element-plus';
export default defineComponent({
name: 'SortableTableDemo',
setup() {
@ -160,7 +159,7 @@
// sortablejs
const handleRowSort = (newIndex, oldIndex, e) => {
console.info('sort', e);
ElMessage.success(`排序从 ${oldIndex} 变成了 ${newIndex} `);
proxy.$message.success(`排序从 ${oldIndex} 变成了 ${newIndex} `);
};
//
const handleRowAdd = (newIndex, oldIndex, tableCode, done, e) => {
@ -168,38 +167,38 @@
if (tableCode === 'child') {
done(queryState.list.find((item) => item.id === '1').childList[oldIndex]);
}
ElMessage.success(`排序从 ${oldIndex} 变成了 ${newIndex} `);
proxy.$message.success(`排序从 ${oldIndex} 变成了 ${newIndex} `);
};
//
const handleRowRemove = (newIndex, oldIndex, e) => {
console.info('remove', e);
ElMessage.success(`排序从 ${oldIndex} 变成了 ${newIndex} `);
proxy.$message.success(`排序从 ${oldIndex} 变成了 ${newIndex} `);
};
//
const handleRowClone = (newIndex, oldIndex, e) => {
console.info('clone', e);
ElMessage.success(`排序从 ${oldIndex} 变成了 ${newIndex} `);
proxy.$message.success(`排序从 ${oldIndex} 变成了 ${newIndex} `);
};
/* 子表格操作 */
const handleChildrenRowSort = (newIndex, oldIndex, e) => {
console.info('child sort', e);
ElMessage.success(`排序从 ${oldIndex} 变成了 ${newIndex} `);
proxy.$message.success(`排序从 ${oldIndex} 变成了 ${newIndex} `);
};
const handleChildrenRowAdd = (newIndex, oldIndex, tableCode, done, e) => {
console.info('child add', e);
if (tableCode === 'parent') {
done(queryState.list[oldIndex]);
}
ElMessage.success(`排序从 ${oldIndex} 变成了 ${newIndex} `);
proxy.$message.success(`排序从 ${oldIndex} 变成了 ${newIndex} `);
};
const handleChildrenRowRemove = (newIndex, oldIndex, e) => {
console.info('child remove', e);
ElMessage.success(`排序从 ${oldIndex} 变成了 ${newIndex} `);
proxy.$message.success(`排序从 ${oldIndex} 变成了 ${newIndex} `);
};
const handleChildrenRowClone = (newIndex, oldIndex, e) => {
console.info('child clone', e);
ElMessage.success(`排序从 ${oldIndex} 变成了 ${newIndex} `);
proxy.$message.success(`排序从 ${oldIndex} 变成了 ${newIndex} `);
};
return {

@ -2,7 +2,7 @@
<div class="mask">
<div class="box">
<div class="logo">
<el-icon name="logo" svg color="#69ADE5" size="50"></el-icon>
<el-icon color="#69ADE5" name="logo" size="50" svg />
</div>
<div class="title">{{ config.projectName }}</div>
<div class="sub">登录您的管理账号</div>
@ -10,14 +10,14 @@
<el-form-item prop="phone">
<el-input v-model="form.phone" class="ghost" placeholder="请输入手机号码">
<template #prefix>
<el-icon class="el-input__icon" name="User"></el-icon>
<el-icon class="el-input__icon" name="User" />
</template>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input v-model="form.password" type="password" class="ghost" placeholder="请输入登录密码">
<el-input v-model="form.password" class="ghost" placeholder="请输入登录密码" type="password">
<template #prefix>
<el-icon class="el-input__icon" name="View"></el-icon>
<el-icon class="el-input__icon" name="View" />
</template>
</el-input>
</el-form-item>
@ -25,15 +25,15 @@
<div class="flex">
<el-input v-model="form.verifyCode" class="ghost" placeholder="请输入验证码">
<template #prefix>
<el-icon class="el-input__icon" name="ChatSquare"></el-icon>
<el-icon class="el-input__icon" name="ChatSquare" />
</template>
</el-input>
<el-button class="ghost" :disabled="waitTime > 0" @click="handleSms" :loading="sending">
<el-button class="ghost" :disabled="waitTime > 0" :loading="sending" @click="handleSms">
{{ waitTime ? waitTime + 'S' : '发送验证码' }}
</el-button>
</div>
</el-form-item>
<el-button class="block" @click="handleLogin" :loading="submitting">立即登录</el-button>
<el-button class="block" :loading="submitting" @click="handleLogin"></el-button>
</el-form>
</div>
</div>

@ -4,18 +4,18 @@
<h1>
<el-icon name="app-store" size="30" />
<span>马士兵严选</span>
<el-icon name="msb" svg size="30"></el-icon>
<el-icon name="vue" svg color="red" size="30" />
<el-icon name="Avatar" color="red" size="30" />
<el-icon name="msb" size="30" svg />
<el-icon color="red" name="vue" size="30" svg />
<el-icon color="red" name="Avatar" size="30" />
</h1>
<p>count:{{ count }}, double count:{{ doubleCount }}</p>
<el-button type="primary" @click="handleAdd"></el-button>
<el-button type="danger" @click="handleClear"></el-button>
<br />
<el-date-picker></el-date-picker>
<el-date-picker />
{{ form }}
<el-input v-model="form.msg" />
<el-editor preview="pc" v-model="form.msg"></el-editor>
<el-editor v-model="form.msg" preview="pc" />
</div>
</template>

@ -1,13 +1,13 @@
<template>
<div class="form-container">
<el-form
class="form-content"
ref="refsForm"
v-loading="loading"
class="form-content"
:disabled="route.name === 'UserDetail'"
label-width="100px"
:model="form"
:rules="rules"
label-width="100px"
:disabled="route.name === 'UserDetail'"
>
<el-form-item label="用户名" prop="username">
<el-input v-model="form.username" />
@ -16,17 +16,17 @@
<el-input v-model="form.nickname" />
</el-form-item>
<el-form-item label="性别" prop="sex">
<el-radio-group :opts="opts.sex" v-model="form.sex" />
<el-radio-group v-model="form.sex" :opts="opts.sex" />
</el-form-item>
<el-form-item label="头像" prop="avatar">
<el-upload-image :disabled="route.name === 'UserDetail'" v-model="form.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="启用"
inactive-text="禁用"
:active-value="true"
inactive-text="禁用"
:inactive-value="false"
/>
</el-form-item>
@ -34,9 +34,9 @@
<div class="form-footer">
<template v-if="route.name !== 'UserDetail'">
<el-button @click="handleCancel"></el-button>
<el-button type="primary" @click="handleSave" :disabled="loading" :loading="submitting">保存</el-button>
<el-button :disabled="loading" :loading="submitting" type="primary" @click="handleSave"></el-button>
</template>
<el-button @click="handleClose" v-else></el-button>
<el-button v-else @click="handleClose"></el-button>
</div>
</div>
</template>

@ -2,17 +2,17 @@
<TableList
v-loading="loading"
code="DemoList"
title="用户"
:config="config"
:data="list"
title="用户"
:total="total"
:config="config"
@search="handleSearch"
@create="handleCreate"
@remove="handleRemove"
@search="handleSearch"
>
<template #search>
<el-form inline>
<el-form-item prop="username" label="用户名">
<el-form-item label="用户名" prop="username">
<el-input v-model="state.condition.username" />
</el-form-item>
</el-form>
@ -53,7 +53,7 @@
router.push({ name: 'UserDetail', params: { id: row.id } });
};
const handleEnabled = (row, enabled) => {
alert((enabled ? 'enabled ' : 'disabled ') + row.id);
console.info((enabled ? 'enabled ' : 'disabled ') + row.id);
};
const config = reactive({
columns: [

@ -11,6 +11,7 @@ import { createSvgIconsPlugin } from 'vite-plugin-svg-icons';
import globalStyle from '@originjs/vite-plugin-global-style';
import removeConsole from 'vite-plugin-remove-console';
import legacy from '@vitejs/plugin-legacy';
import eslintPlugin from '@nabla/vite-plugin-eslint';
export default ({ command, mode }: ConfigEnv): UserConfigExport => {
console.info('command', command);
@ -92,6 +93,12 @@ export default ({ command, mode }: ConfigEnv): UserConfigExport => {
legacy({
targets: ['defaults', 'not IE 11'],
}),
eslintPlugin({
eslintOptions: {
cache: true,
},
shouldLint: (path) => /\/src\/[^?]*\.(vue|m?[jt]sx?)$/.test(path),
}),
],
css: {
preprocessorOptions: {

Loading…
Cancel
Save