Skip to content

Commit

Permalink
feat: init fe
Browse files Browse the repository at this point in the history
  • Loading branch information
wmui committed Jul 10, 2023
1 parent acede19 commit 079f7e4
Show file tree
Hide file tree
Showing 96 changed files with 3,306 additions and 1,508 deletions.
File renamed without changes.
Empty file added fe/.env.production
Empty file.
Empty file added fe/.env.test
Empty file.
5 changes: 3 additions & 2 deletions frontend/.eslintrc.cjs → fe/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ module.exports = {
'extends': [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-typescript',
'@vue/eslint-config-prettier/skip-formatting'
],
parserOptions: {
ecmaVersion: 'latest'
}
},
rules: {
}
}
File renamed without changes.
File renamed without changes.
3 changes: 3 additions & 0 deletions fe/.vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"recommendations": ["Vue.volar"]
}
File renamed without changes.
2 changes: 1 addition & 1 deletion frontend/index.html → fe/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
<script type="module" src="/src/main.js"></script>
</body>
</html>
16 changes: 5 additions & 11 deletions frontend/package.json → fe/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,30 @@
"dev": "vite",
"build": "run-p type-check build-only",
"preview": "vite preview",
"test:unit": "vitest",
"build-only": "vite build",
"type-check": "vue-tsc --noEmit -p tsconfig.vitest.json --composite false",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
"format": "prettier --write src/"
},
"dependencies": {
"axios": "^1.4.0",
"element-plus": "^2.3.7",
"pinia": "^2.1.3",
"vue": "^3.3.4",
"vue-router": "^4.2.2"
"vue-router": "^4.2.2",
"vuex": "^4.1.0"
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.2.0",
"@tsconfig/node18": "^2.0.1",
"@types/jsdom": "^21.1.1",
"@types/node": "^18.16.17",
"@vitejs/plugin-vue": "^4.2.3",
"@vitejs/plugin-vue-jsx": "^3.0.1",
"@vue/eslint-config-prettier": "^7.1.0",
"@vue/eslint-config-typescript": "^11.0.3",
"@vue/test-utils": "^2.3.2",
"@vue/tsconfig": "^0.4.0",
"eslint": "^8.39.0",
"eslint-plugin-vue": "^9.11.0",
"jsdom": "^22.1.0",
"less": "^4.1.3",
"npm-run-all": "^4.1.5",
"prettier": "^2.8.8",
"typescript": "~5.0.4",
"vite": "^4.3.9",
"vitest": "^0.32.0",
"vue-tsc": "^1.6.5"
}
}
57 changes: 57 additions & 0 deletions fe/packages/BaseTable/BaseTable.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<template>
<div class="base-table">
<div class="action">
<slot name="action"></slot>
</div>
<!-- data、selection-change 等属性和事件都直接透传给 el-table -->
<el-table v-bind="$attrs">
<el-table-column type="selection" width="55" v-if="selection" />
<template v-for="item in columns" :key="item.prop">
<!-- label、prop、width、formatter 等都通过 v-bind="item" 赋值给 el-table-column -->
<el-table-column v-if="!item.type" v-bind="item" />
<el-table-column v-else-if="item.type === 'action'" v-bind="item">
<template #default="scope">
<template v-for="(btn, index) in item.list" :key="btn.text">
<el-button :type="btn.type || 'text'" size="small" @click="handleAction(index, scope.row)">{{ btn.text }}</el-button>
</template>
</template>
</el-table-column>
</template>
</el-table>
<el-pagination
class="pagination" background layout="prev, pager, next"
:total="pager.total" :page-size="pager.pageSize"
@current-change="handleCurrentChange"
/>
</div>
</template>

<script>
export default {
name: 'BaseTable',
props: {
columns: Array,
selection: Boolean,
pager: Object
},
setup (props, context) {
const handleAction = (index, row) => {
context.emit('handleAction', {
index,
row: {
...row // 通过解构让 row 从响应式变为普通对象
}
})
}
const handleCurrentChange = pageNum => {
context.emit('handleCurrentChange', pageNum)
}
return {
handleAction,
handleCurrentChange
}
}
}
</script>
7 changes: 7 additions & 0 deletions fe/packages/BaseTable/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import BaseTable from './BaseTable.vue'

BaseTable.install = app => {
app.component(BaseTable.name, BaseTable)
}

export default BaseTable
34 changes: 34 additions & 0 deletions fe/packages/QueryForm/FormItem.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<template>
<!--
外部 <FormItem v-bind="item" /> 会把 item 这个 JSON 配置项对象中的 label 透传给 el-form-item
el-form-item 上的 prop 用于重置表单和规则校验,prop 可以像这样直接写,也可以配置在传递给 QueryForm 的 form 这个 JSON 对象中
-->
<el-form-item :prop="item.model">
<!--
v-bind="$attrs" 的 $attrs 是除去 props 和 emits 后外部透传过来的属性
这里直接赋值给这些 element-plus 组件,是因为配置的 JSON 中有 model 和 placeholder 等属性
这些属性可以通过 v-bind 直接透传给 element-plus 组件
另外这些 element-plus 组件可以用 component 组件配合 is 属性来使用,扩展性更好
-->
<el-input v-if="item.type === 'input'" v-bind="$attrs" />
<el-select v-else-if="item.type === 'select'" v-bind="$attrs">
<!--
v-bind="option" 相当于把 option 中的属性都绑定到 el-option 中
如 :label="option.label" :value="option.value"
-->
<el-option v-for="option in item.options" :key="option.value" v-bind="option" />
</el-select>
</el-form-item>
</template>

<script>
export default {
name: 'FormItem',
/**
* element-plus 的组件用 v-bind="$attrs" 接收了不在 props 定义的属性
* 其中 <FormItem v-model /> v-model 的 modelValue 也需要传给 element-plus 组件
* 所以就不能在 props 中定义 modelValue
*/
props: ['item']
}
</script>
52 changes: 52 additions & 0 deletions fe/packages/QueryForm/QueryForm.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<template>
<el-form ref="queryForm" inline :model="queryModel">
<template v-for="(item, index) in form" :key="item.model">
<!-- v-bind="item" 会把 item 对象的所有属性绑定到 FormItem 内根元素上,如 :label="item.label" -->
<FormItem :item="item" v-bind="item" v-model="queryModel[item.model]" />
</template>
<el-form-item>
<el-button type="primary" @click="handleQuery">查询</el-button>
<el-button @click="handleReset">重置</el-button>
</el-form-item>
</el-form>
</template>

<script>
import { reactive, getCurrentInstance } from 'vue'
import FormItem from './FormItem.vue'
export default {
name: 'QueryForm',
/**
* form 是一个 JSON 对象
* modelValue 是 v-model 的默认值,即 v-model:modelValue
* v-model 本质是 modelValue 和 @update:modelValue 的语法糖
*/
props: ['form', 'modelValue'],
emits: ['update:modelValue'],
components: { FormItem },
setup (props, context) {
const { ctx } = getCurrentInstance()
const queryModel = reactive({
...props.modelValue
})
const { form } = props
const handleQuery = () => {
// 触发的 update:modelValue 会把值传递给 <QueryForm v-model="user" /> 中 v-model 绑定的 user 对象
context.emit('update:modelValue', { ...queryModel })
context.emit('handleQuery') // handleQuery 要放后面,这样 v-model 的值改变后再重新查询
}
const handleReset = () => {
ctx.$refs.queryForm.resetFields()
}
return {
queryModel,
form,
handleQuery,
handleReset
}
}
}
</script>
9 changes: 9 additions & 0 deletions fe/packages/QueryForm/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import QueryForm from './QueryForm.vue'

// app.use(QueryForm) 来使用
// Vue 的插件都需要暴露出 install 方法,接受一个 Vue 实例参数 app
QueryForm.install = app => {
app.component(QueryForm.name, QueryForm)
}

export default QueryForm
8 changes: 8 additions & 0 deletions fe/packages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import QueryForm from './QueryForm'
import BaseTable from './BaseTable'

export default {
install (app) {
app.use(QueryForm).use(BaseTable)
}
}
File renamed without changes.
15 changes: 15 additions & 0 deletions fe/src/App.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<template>
<!-- 这个 router-view 用于显示顶级路由的组件,如 '/' 对应的 Home 组件 -->
<router-view></router-view>
</template>

<script>
export default {
name: 'App'
}
</script>

<style lang="less">
@import '@/assets/styles/reset.css';
@import '@/assets/styles/index.css';
</style>
Loading

0 comments on commit 079f7e4

Please sign in to comment.