错误提交

pull/120/MERGE
gexinzhineng/gxzn27 2023-04-03 16:11:12 +08:00
parent 0e578f8d0a
commit b967c4e01e
38 changed files with 344 additions and 158 deletions

2
.gitignore vendored
View File

@ -8,4 +8,4 @@ dist-ssr
pnpm-debug
.idea
.history
.history

View File

@ -15,7 +15,7 @@ import vueSetupExtend from 'vite-plugin-vue-setup-extend'
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
export function createVitePlugins(VITE_APP_TITLE: string) {
export function createVitePlugins() {
const root = process.cwd()
// 路径查找
function pathResolve(dir: string) {
@ -39,11 +39,14 @@ export function createVitePlugins(VITE_APP_TITLE: string) {
imports: [
'vue',
'vue-router',
// 可额外添加需要 autoImport 的组件
{
'@/hooks/web/useI18n': ['useI18n'],
'@/hooks/web/useXTable': ['useXTable'],
'@/hooks/web/useMessage': ['useMessage'],
'@/hooks/web/useXTable': ['useXTable'],
'@/hooks/web/useVxeCrudSchemas': ['useVxeCrudSchemas'],
'@/hooks/web/useTable': ['useTable'],
'@/hooks/web/useCrudSchemas': ['useCrudSchemas'],
'@/utils/formRules': ['required'],
'@/utils/dict': ['DICT_TYPE']
}
@ -92,8 +95,6 @@ export function createVitePlugins(VITE_APP_TITLE: string) {
ext: '.gz', // 生成的压缩包后缀
deleteOriginFile: false //压缩后是否删除源文件
}),
ViteEjsPlugin({
title: VITE_APP_TITLE
})
ViteEjsPlugin()
]
}

View File

@ -13,7 +13,7 @@
name="description"
content="芋道管理系统 基于 vue3 + CompositionAPI + typescript + vite3 + element plus 的后台开源免费管理系统!"
/>
<title><%= title %></title>
<title>%VITE_APP_TITLE%</title>
</head>
<body>
<div id="app">
@ -137,7 +137,7 @@
<div class="app-loading-wrap">
<div class="app-loading-title">
<img src="/logo.gif" class="app-loading-logo" alt="Logo" />
<div class="app-loading-title"><%= title %></div>
<div class="app-loading-title">%VITE_APP_TITLE%</div>
</div>
<div class="app-loading-item">
<div class="app-loading-outter"></div>

View File

@ -1,6 +1,6 @@
{
"name": "yudao-ui-admin-vue3",
"version": "1.7.1-snapshot.1941",
"version": "1.7.1-snapshot.1961",
"description": "基于vue3、vite4、element-plus、typesScript",
"author": "xingyu",
"private": false,
@ -29,12 +29,14 @@
"@form-create/designer": "^3.1.0",
"@form-create/element-ui": "^3.1.17",
"@iconify/iconify": "^3.1.0",
"@videojs-player/vue": "^1.0.0",
"@vueuse/core": "^9.13.0",
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "^5.1.10",
"@zxcvbn-ts/core": "^2.2.1",
"animate.css": "^4.1.1",
"axios": "^1.3.4",
"benz-amr-recorder": "^1.1.5",
"bpmn-js-token-simulation": "^0.10.0",
"camunda-bpmn-moddle": "^7.0.1",
"cropperjs": "^1.5.13",
@ -43,7 +45,7 @@
"diagram-js": "^11.6.0",
"echarts": "^5.4.1",
"echarts-wordcloud": "^2.1.0",
"element-plus": "2.2.34",
"element-plus": "2.3.1",
"fast-xml-parser": "^4.1.3",
"highlight.js": "^11.7.0",
"intro.js": "^6.0.0",
@ -57,62 +59,63 @@
"qs": "^6.11.1",
"steady-xml": "^0.1.0",
"url": "^0.11.0",
"video.js": "^8.0.4",
"vue": "3.2.47",
"vue-i18n": "9.2.2",
"vue-router": "^4.1.6",
"vue-types": "^5.0.2",
"vuedraggable": "^4.1.0",
"vxe-table": "^4.3.10",
"vxe-table": "^4.3.11",
"web-storage-cache": "^1.1.1",
"xe-utils": "^3.5.7",
"xml-js": "^1.6.11"
},
"devDependencies": {
"@commitlint/cli": "^17.4.4",
"@commitlint/cli": "^17.5.0",
"@commitlint/config-conventional": "^17.4.4",
"@iconify/json": "^2.2.31",
"@intlify/unplugin-vue-i18n": "^0.8.2",
"@iconify/json": "^2.2.38",
"@intlify/unplugin-vue-i18n": "^0.10.0",
"@purge-icons/generated": "^0.9.0",
"@types/intro.js": "^5.1.1",
"@types/lodash-es": "^4.17.6",
"@types/node": "^18.14.6",
"@types/lodash-es": "^4.17.7",
"@types/node": "^18.15.5",
"@types/nprogress": "^0.2.0",
"@types/qrcode": "^1.5.0",
"@types/qs": "^6.9.7",
"@typescript-eslint/eslint-plugin": "^5.54.1",
"@typescript-eslint/parser": "^5.54.1",
"@vitejs/plugin-legacy": "^4.0.1",
"@vitejs/plugin-vue": "^4.0.0",
"@vitejs/plugin-vue-jsx": "^3.0.0",
"autoprefixer": "^10.4.13",
"@typescript-eslint/eslint-plugin": "^5.56.0",
"@typescript-eslint/parser": "^5.56.0",
"@vitejs/plugin-legacy": "^4.0.2",
"@vitejs/plugin-vue": "^4.1.0",
"@vitejs/plugin-vue-jsx": "^3.0.1",
"autoprefixer": "^10.4.14",
"bpmn-js": "^8.9.0",
"bpmn-js-properties-panel": "^0.46.0",
"consola": "^2.15.3",
"eslint": "^8.35.0",
"eslint-config-prettier": "^8.7.0",
"eslint-define-config": "^1.15.0",
"eslint": "^8.36.0",
"eslint-config-prettier": "^8.8.0",
"eslint-define-config": "^1.17.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-vue": "^9.9.0",
"lint-staged": "^13.1.2",
"lint-staged": "^13.2.0",
"postcss": "^8.4.21",
"postcss-html": "^1.5.0",
"postcss-scss": "^4.0.6",
"prettier": "^2.8.4",
"rimraf": "^4.3.1",
"rollup": "^3.18.0",
"sass": "^1.58.3",
"stylelint": "^15.2.0",
"prettier": "^2.8.6",
"rimraf": "^4.4.1",
"rollup": "^3.20.0",
"sass": "^1.59.3",
"stylelint": "^15.3.0",
"stylelint-config-html": "^1.1.0",
"stylelint-config-prettier": "^9.0.5",
"stylelint-config-recommended": "^10.0.1",
"stylelint-config-standard": "^30.0.1",
"stylelint-order": "^6.0.2",
"terser": "^5.16.5",
"typescript": "4.9.5",
"stylelint-config-recommended": "^11.0.0",
"stylelint-config-standard": "^31.0.0",
"stylelint-order": "^6.0.3",
"terser": "^5.16.6",
"typescript": "5.0.2",
"unplugin-auto-import": "^0.15.1",
"unplugin-element-plus": "^0.7.0",
"unplugin-vue-components": "^0.24.1",
"vite": "4.1.4",
"vite": "4.2.1",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-ejs": "^1.6.4",
"vite-plugin-eslint": "^1.8.1",
@ -125,7 +128,7 @@
"windicss": "^3.5.6"
},
"engines": {
"node": ">=16.0.0"
"node": ">=16.18.0"
},
"license": "MIT",
"repository": {

View File

@ -1,5 +1,10 @@
import request from '@/config/axios'
export interface AccountVO {
id?: number
name: string
}
// 创建公众号账号
export const createAccount = async (data) => {
return await request.post({ url: '/mp/account/create', data })
@ -26,7 +31,7 @@ export const getAccountPage = async (query) => {
}
// 获取公众号账号精简信息列表
export const getSimpleAccounts = async () => {
export const getSimpleAccountList = async () => {
return request.get({ url: '/mp/account/list-all-simple' })
}

View File

@ -1,7 +1,7 @@
import request from '@/config/axios'
// 获得公众号消息分页
export const getMessagePage = (query) => {
export const getMessagePage = (query: PageParam) => {
return request.get({
url: '/mp/message/page',
params: query

View File

@ -1,7 +1,14 @@
import request from '@/config/axios'
export interface TagVO {
id?: number
name: string
accountId: number
createTime: Date
}
// 创建公众号标签
export const createTag = (data) => {
export const createTag = (data: TagVO) => {
return request.post({
url: '/mp/tag/create',
data: data
@ -9,7 +16,7 @@ export const createTag = (data) => {
}
// 更新公众号标签
export const updateTag = (data) => {
export const updateTag = (data: TagVO) => {
return request.put({
url: '/mp/tag/update',
data: data
@ -17,21 +24,21 @@ export const updateTag = (data) => {
}
// 删除公众号标签
export const deleteTag = (id) => {
export const deleteTag = (id: number) => {
return request.delete({
url: '/mp/tag/delete?id=' + id
})
}
// 获得公众号标签
export const getTag = (id) => {
export const getTag = (id: number) => {
return request.get({
url: '/mp/tag/get?id=' + id
})
}
// 获得公众号标签分页
export const getTagPage = (query) => {
export const getTagPage = (query: PageParam) => {
return request.get({
url: '/mp/tag/page',
params: query
@ -39,14 +46,14 @@ export const getTagPage = (query) => {
}
// 获取公众号标签精简信息列表
export const getSimpleTags = () => {
export const getSimpleTagList = () => {
return request.get({
url: '/mp/tag/list-all-simple'
})
}
// 同步公众号标签
export const syncTag = (accountId) => {
export const syncTag = (accountId: number) => {
return request.post({
url: '/mp/tag/sync?accountId=' + accountId
})

View File

@ -13,7 +13,7 @@ defineProps({
</script>
<template>
<ElCard :class="[prefixCls, 'mb-20px']" shadow="never">
<ElCard :class="[prefixCls, 'mb-15px']" shadow="never">
<template v-if="title" #header>
<div class="flex items-center">
<span class="text-16px font-700">{{ title }}</span>

View File

@ -6,7 +6,10 @@ interface shortcutsType {
value: string
}
const props = defineProps({
modelValue: { type: String, default: '* * * * * ?' },
modelValue: {
type: String,
default: '* * * * * ?'
},
shortcuts: { type: Array as PropType<shortcutsType[]>, default: () => [] }
})
const defaultValue = ref('')

View File

@ -76,7 +76,7 @@ const toggleClick = () => {
v-if="title"
:class="[
`${prefixCls}-header`,
'h-50px flex justify-between items-center mb-10px border-bottom-1 border-solid border-[var(--tags-view-border-color)] px-10px cursor-pointer dark:border-[var(--el-border-color)]'
'h-50px flex justify-between items-center border-bottom-1 border-solid border-[var(--tags-view-border-color)] px-10px cursor-pointer dark:border-[var(--el-border-color)]'
]"
@click="toggleClick"
>

View File

@ -34,7 +34,7 @@ export default defineComponent({
return null
}
//
if (props.value === undefined) {
if (props.value === undefined || props.value === null) {
return null
}
getDictObj(props.type, props.value.toString())

View File

@ -178,7 +178,7 @@ defineExpose({
</script>
<template>
<div class="border-1 border-solid border-[var(--tags-view-border-color)] z-3000">
<div class="border-1 border-solid border-[var(--tags-view-border-color)] z-99">
<!-- 工具栏 -->
<Toolbar
:editor="editorRef"

View File

@ -35,7 +35,8 @@ export default defineComponent({
default: () => []
},
//
isCol: propTypes.bool.def(true),
// update by true false
isCol: propTypes.bool.def(false),
//
model: {
type: Object as PropType<Recordable>,
@ -46,7 +47,9 @@ export default defineComponent({
//
isCustom: propTypes.bool.def(false),
// label
labelWidth: propTypes.oneOfType([String, Number]).def('auto')
labelWidth: propTypes.oneOfType([String, Number]).def('auto'),
// loading add by
vLoading: propTypes.bool.def(false)
},
emits: ['register'],
setup(props, { slots, expose, emit }) {
@ -280,6 +283,7 @@ export default defineComponent({
{...getFormBindValue()}
model={props.isCustom ? props.model : formModel}
class={prefixCls}
v-loading={props.vLoading}
>
{{
//

View File

@ -5,7 +5,7 @@
class="float-right mt-15px mb-15px"
:background="true"
layout="total, sizes, prev, pager, next, jumper"
:page-sizes="[10, 20, 30, 50]"
:page-sizes="[10, 20, 30, 50, 100]"
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:pager-count="pagerCount"

View File

@ -98,6 +98,7 @@ const setVisible = () => {
</script>
<template>
<!-- update by 芋艿class="-mb-15px" 用于降低和 ContentWrap 组件的底部距离避免空隙过大 -->
<Form
:is-custom="false"
:label-width="labelWidth"
@ -106,21 +107,26 @@ const setVisible = () => {
:is-col="isCol"
:schema="newSchema"
@register="register"
class="-mb-15px"
>
<template #action>
<div v-if="layout === 'inline'">
<ElButton v-if="showSearch" type="primary" @click="search">
<!-- update by 芋艿去除搜索的 type="primary"颜色变淡一点 -->
<ElButton v-if="showSearch" @click="search">
<Icon icon="ep:search" class="mr-5px" />
{{ t('common.query') }}
</ElButton>
<!-- update by 芋艿 icon="ep:refresh-right" 修改成 icon="ep:refresh" ruoyi-vue 搜索保持一致 -->
<ElButton v-if="showReset" @click="reset">
<Icon icon="ep:refresh-right" class="mr-5px" />
<Icon icon="ep:refresh" class="mr-5px" />
{{ t('common.reset') }}
</ElButton>
<ElButton v-if="expand" text @click="setVisible">
{{ t(visible ? 'common.shrink' : 'common.expand') }}
<Icon :icon="visible ? 'ep:arrow-up' : 'ep:arrow-down'" />
</ElButton>
<!-- add by 芋艿补充在搜索后的按钮 -->
<slot name="actionMore"></slot>
</div>
</template>
<template #[name] v-for="name in Object.keys($slots)" :key="name"
@ -142,6 +148,8 @@ const setVisible = () => {
{{ t(visible ? 'common.shrink' : 'common.expand') }}
<Icon :icon="visible ? 'ep:arrow-up' : 'ep:arrow-down'" />
</ElButton>
<!-- add by 芋艿补充在搜索后的按钮 -->
<slot name="actionMore"></slot>
</div>
</template>
</template>

View File

@ -104,11 +104,12 @@ export default defineComponent({
})
const pagination = computed(() => {
// update by Pagination
return Object.assign(
{
small: false,
background: true,
pagerCount: 5,
pagerCount: document.body.clientWidth < 992 ? 5 : 7,
layout: 'total, sizes, prev, pager, next, jumper',
pageSizes: [10, 20, 30, 50, 100],
disabled: false,
@ -283,10 +284,11 @@ export default defineComponent({
}}
</ElTable>
{unref(getProps).pagination ? (
// update by Pagination
<ElPagination
v-model:pageSize={pageSizeRef.value}
v-model:currentPage={currentPageRef.value}
class="mt-10px"
class="float-right mt-15px mb-15px"
{...unref(pagination)}
></ElPagination>
) : undefined}

View File

@ -8,6 +8,7 @@ import { FormSchema } from '@/types/form'
import { TableColumn } from '@/types/table'
import { DescriptionsSchema } from '@/types/descriptions'
import { ComponentOptions, ComponentProps } from '@/types/components'
import { DictTag } from '@/components/DictTag'
export type CrudSchema = Omit<TableColumn, 'children'> & {
isSearch?: boolean // 是否在查询显示
@ -151,6 +152,15 @@ const filterTableSchema = (crudSchema: CrudSchema[]): TableColumn[] => {
const tableColumns = treeMap<CrudSchema>(crudSchema, {
conversion: (schema: CrudSchema) => {
if (schema?.isTable !== false && schema?.table?.show !== false) {
// add by 芋艿:增加对 dict 字典数据的支持
if (!schema.formatter && schema.dictType) {
schema.formatter = (_: Recordable, __: TableColumn, cellValue: any) => {
return h(DictTag, {
type: schema.dictType!, // ! 表示一定不为空
value: cellValue
})
}
}
return {
...schema.table,
...schema

View File

@ -218,6 +218,8 @@ export const useTable = <T = any>(config?: UseTableConfig<T>) => {
register,
elTableRef,
tableObject,
methods
methods,
// add by 芋艿:返回 tableMethods 属性,和 tableObject 更统一
tableMethods: methods
}
}

View File

@ -37,7 +37,7 @@ export default defineComponent({
})
const getBreadcrumb = () => {
const currentPath = currentRoute.value.path
const currentPath = currentRoute.value.matched.slice(-1)[0].path
levelList.value = filter<AppRouteRecordRaw>(unref(menuRouters), (node: AppRouteRecordRaw) => {
return node.path === currentPath
@ -47,7 +47,7 @@ export default defineComponent({
const renderBreadcrumb = () => {
const breadcrumbList = treeToList<AppRouteRecordRaw[]>(unref(levelList))
return breadcrumbList.map((v) => {
const disabled = v.redirect === 'noredirect'
const disabled = !v.redirect || v.redirect === 'noredirect'
const meta = v.meta as RouteMeta
return (
<ElBreadcrumbItem to={{ path: disabled ? '' : v.path }} key={v.name}>

View File

@ -1,5 +1,5 @@
<script setup lang="ts">
import dayjs from 'dayjs'
import { parseTime } from '@/utils/formatTime'
import * as NotifyMessageApi from '@/api/system/notify/message'
const { push } = useRouter()
@ -57,7 +57,7 @@ onMounted(() => {
{{ item.templateNickname }}{{ item.templateContent }}
</span>
<span class="message-date">
{{ dayjs(item.createTime).format('YYYY-MM-DD HH:mm:ss') }}
{{ parseTime(item.createTime) }}
</span>
</div>
</div>

View File

@ -297,7 +297,8 @@ export default {
typeCreate: 'Dict Type Create',
typeUpdate: 'Dict Type Eidt',
dataCreate: 'Dict Data Create',
dataUpdate: 'Dict Data Eidt'
dataUpdate: 'Dict Data Eidt',
fileUpload: 'File Upload'
},
dialog: {
dialog: 'Dialog',

View File

@ -297,7 +297,8 @@ export default {
typeCreate: '字典类型新增',
typeUpdate: '字典类型编辑',
dataCreate: '字典数据新增',
dataUpdate: '字典数据编辑'
dataUpdate: '字典数据编辑',
fileUpload: '上传文件'
},
dialog: {
dialog: '弹窗',

View File

@ -104,6 +104,31 @@ const remainingRouter: AppRouteRecordRaw[] = [
}
]
},
{
path: '/dict',
component: Layout,
name: 'dict',
meta: {
hidden: true
},
children: [
{
path: 'type/data/:dictType',
component: () => import('@/views/system/dict/data.vue'),
name: 'data',
meta: {
title: '字典数据',
noCache: true,
hidden: true,
canTo: true,
icon: '',
activeMenu: 'system/dict/data'
}
}
]
},
{
path: '/codegen',
component: Layout,
@ -137,7 +162,7 @@ const remainingRouter: AppRouteRecordRaw[] = [
children: [
{
path: 'job-log',
component: () => import('@/views/infra/job/JobLog.vue'),
component: () => import('@/views/infra/job/logger/index.vue'),
name: 'JobLog',
meta: {
noCache: true,
@ -200,26 +225,26 @@ const remainingRouter: AppRouteRecordRaw[] = [
children: [
{
path: '/manager/form/edit',
component: () => import('@/views/bpm/form/formEditor.vue'),
component: () => import('@/views/bpm/form/editor/index.vue'),
name: 'bpmFormEditor',
meta: {
noCache: true,
hidden: true,
canTo: true,
title: '设计流程表单',
activeMenu: 'bpm/manager/form/formEditor'
activeMenu: '/bpm/manager/form'
}
},
{
path: '/manager/model/edit',
component: () => import('@/views/bpm/model/modelEditor.vue'),
component: () => import('@/views/bpm/model/editor/index.vue'),
name: 'modelEditor',
meta: {
noCache: true,
hidden: true,
canTo: true,
title: '设计流程',
activeMenu: 'bpm/manager/model/design'
activeMenu: '/bpm/manager/model'
}
},
{
@ -231,7 +256,7 @@ const remainingRouter: AppRouteRecordRaw[] = [
hidden: true,
canTo: true,
title: '流程定义',
activeMenu: 'bpm/definition/index'
activeMenu: '/bpm/manager/model'
}
},
{
@ -247,7 +272,7 @@ const remainingRouter: AppRouteRecordRaw[] = [
},
{
path: '/process-instance/create',
component: () => import('@/views/bpm/processInstance/create.vue'),
component: () => import('@/views/bpm/processInstance/create/index.vue'),
name: 'BpmProcessInstanceCreate',
meta: {
noCache: true,
@ -259,7 +284,7 @@ const remainingRouter: AppRouteRecordRaw[] = [
},
{
path: '/process-instance/detail',
component: () => import('@/views/bpm/processInstance/detail.vue'),
component: () => import('@/views/bpm/processInstance/detail/index.vue'),
name: 'BpmProcessInstanceDetail',
meta: {
noCache: true,
@ -294,6 +319,22 @@ const remainingRouter: AppRouteRecordRaw[] = [
}
}
]
},
{
path: '/property',
component: Layout,
name: 'property',
meta: {
hidden: true
},
children: [
{
path: 'value/:propertyId(\\d+)',
component: () => import('@/views/mall/product/property/value/index.vue'),
name: 'PropertyValue',
meta: { title: '商品属性值', icon: '', activeMenu: '/product/property' }
}
]
}
]

View File

@ -3,7 +3,7 @@ import { store } from '../index'
import { DictDataVO } from '@/api/system/dict/types'
import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
const { wsCache } = useCache('sessionStorage')
import { listSimpleDictDataApi } from '@/api/system/dict/dict.data'
import { listSimpleDictData } from '@/api/system/dict/dict.data'
export interface DictValueType {
value: any
@ -44,7 +44,7 @@ export const useDictStore = defineStore('dict', {
this.dictMap = dictMap
this.isSetDict = true
} else {
const res = await listSimpleDictDataApi()
const res = await listSimpleDictData()
// 设置数据
const dictDataMap = new Map<string, any>()
res.forEach((dictData: DictDataVO) => {
@ -74,7 +74,7 @@ export const useDictStore = defineStore('dict', {
},
async resetDict() {
wsCache.delete(CACHE_KEY.DICT_CACHE)
const res = await listSimpleDictDataApi()
const res = await listSimpleDictData()
// 设置数据
const dictDataMap = new Map<string, any>()
res.forEach((dictData: DictDataVO) => {

View File

@ -24,7 +24,6 @@ declare module '@vue/runtime-core' {
Echart: typeof import('./../components/Echart/src/Echart.vue')['default']
Editor: typeof import('./../components/Editor/src/Editor.vue')['default']
ElAutoResizer: typeof import('element-plus/es')['ElAutoResizer']
ElAvatar: typeof import('element-plus/es')['ElAvatar']
ElBadge: typeof import('element-plus/es')['ElBadge']
ElButton: typeof import('element-plus/es')['ElButton']
ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
@ -69,10 +68,10 @@ declare module '@vue/runtime-core' {
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
ElSelect: typeof import('element-plus/es')['ElSelect']
ElSkeleton: typeof import('element-plus/es')['ElSkeleton']
ElSpace: typeof import('element-plus/es')['ElSpace']
ElSwitch: typeof import('element-plus/es')['ElSwitch']
ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElTableV2: typeof import('element-plus/es')['ElTableV2']
ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs']
ElTag: typeof import('element-plus/es')['ElTag']

View File

@ -52,6 +52,7 @@ declare global {
const triggerRef: typeof import('vue')['triggerRef']
const unref: typeof import('vue')['unref']
const useAttrs: typeof import('vue')['useAttrs']
const useCrudSchemas: typeof import('@/hooks/web/useCrudSchemas')['useCrudSchemas']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVars: typeof import('vue')['useCssVars']
const useI18n: typeof import('@/hooks/web/useI18n')['useI18n']
@ -60,6 +61,7 @@ declare global {
const useRoute: typeof import('vue-router')['useRoute']
const useRouter: typeof import('vue-router')['useRouter']
const useSlots: typeof import('vue')['useSlots']
const useTable: typeof import('@/hooks/web/useTable')['useTable']
const useVxeCrudSchemas: typeof import('@/hooks/web/useVxeCrudSchemas')['useVxeCrudSchemas']
const useXTable: typeof import('@/hooks/web/useXTable')['useXTable']
const watch: typeof import('vue')['watch']

View File

@ -8,6 +8,6 @@ export interface DescriptionsSchema {
labelAlign?: 'left' | 'center' | 'right'
className?: string
labelClassName?: string
dateFormat?: string
dictType?: string
dateFormat?: string // add by 星语:支持时间的格式化
dictType?: string // add by 星语:支持 dict 字典数据
}

View File

@ -70,6 +70,23 @@ export const getDictObj = (dictType: string, value: any) => {
})
}
/**
*
*
* @param dictType
* @param value
*/
export const getDictLabel = (dictType: string, value: any) => {
const dictOptions: DictDataType[] = getDictOptions(dictType)
const dictLabel = ref('')
dictOptions.forEach((dict: DictDataType) => {
if (dict.value === value) {
dictLabel.value = dict.label
}
})
return dictLabel.value
}
export enum DICT_TYPE {
USER_TYPE = 'user_type',
COMMON_STATUS = 'common_status',
@ -123,5 +140,9 @@ export enum DICT_TYPE {
PAY_ORDER_STATUS = 'pay_order_status', // 商户支付订单状态
PAY_ORDER_REFUND_STATUS = 'pay_order_refund_status', // 商户支付订单退款状态
PAY_REFUND_ORDER_STATUS = 'pay_refund_order_status', // 退款订单状态
PAY_REFUND_ORDER_TYPE = 'pay_refund_order_type' // 退款订单类别
PAY_REFUND_ORDER_TYPE = 'pay_refund_order_type', // 退款订单类别
// ========== MP 模块 ==========
MP_AUTO_REPLY_REQUEST_MATCH = 'mp_auto_reply_request_match', // 自动回复请求匹配类型
MP_MESSAGE_TYPE = 'mp_message_type' // 消息类型
}

View File

@ -11,58 +11,63 @@ import dayjs from 'dayjs'
* @description format + + "YYYY-mm-dd HH:MM:SS WWW QQQQ ZZZ"
* @returns
*/
export function formatDate(date: Date, format: string): string {
const we = date.getDay() // 星期
const z = getWeek(date) // 周
const qut = Math.floor((date.getMonth() + 3) / 3).toString() // 季度
const opt: { [key: string]: string } = {
'Y+': date.getFullYear().toString(), // 年
'm+': (date.getMonth() + 1).toString(), // 月(月份从0开始要+1)
'd+': date.getDate().toString(), // 日
'H+': date.getHours().toString(), // 时
'M+': date.getMinutes().toString(), // 分
'S+': date.getSeconds().toString(), // 秒
'q+': qut // 季度
export function formatDate(date: Date, format?: string): string {
// 日期不存在,则返回空
if (!date) {
return ''
}
// 中文数字 (星期)
const week: { [key: string]: string } = {
'0': '日',
'1': '一',
'2': '二',
'3': '三',
'4': '四',
'5': '五',
'6': '六'
// 日期存在,则进行格式化
if (format === undefined) {
format = 'YYYY-MM-DD HH:mm:ss'
}
// 中文数字(季度)
const quarter: { [key: string]: string } = {
'1': '一',
'2': '二',
'3': '三',
'4': '四'
return dayjs(date).format(format)
}
// TODO 芋艿:稍后去掉
// 日期格式化
export function parseTime(time: any, pattern?: string) {
if (arguments.length === 0 || !time) {
return null
}
if (/(W+)/.test(format))
format = format.replace(
RegExp.$1,
RegExp.$1.length > 1 ? (RegExp.$1.length > 2 ? '星期' + week[we] : '周' + week[we]) : week[we]
)
if (/(Q+)/.test(format))
format = format.replace(
RegExp.$1,
RegExp.$1.length == 4 ? '第' + quarter[qut] + '季度' : quarter[qut]
)
if (/(Z+)/.test(format))
format = format.replace(RegExp.$1, RegExp.$1.length == 3 ? '第' + z + '周' : z + '')
for (const k in opt) {
const r = new RegExp('(' + k + ')').exec(format)
// 若输入的长度不为1则前面补零
if (r)
format = format.replace(
r[1],
RegExp.$1.length == 1 ? opt[k] : opt[k].padStart(RegExp.$1.length, '0')
)
const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}'
let date
if (typeof time === 'object') {
date = time
} else {
if (typeof time === 'string' && /^[0-9]+$/.test(time)) {
time = parseInt(time)
} else if (typeof time === 'string') {
time = time
.replace(new RegExp(/-/gm), '/')
.replace('T', ' ')
.replace(new RegExp(/\.\d{3}/gm), '')
}
if (typeof time === 'number' && time.toString().length === 10) {
time = time * 1000
}
date = new Date(time)
}
return format
const formatObj = {
y: date.getFullYear(),
m: date.getMonth() + 1,
d: date.getDate(),
h: date.getHours(),
i: date.getMinutes(),
s: date.getSeconds(),
a: date.getDay()
}
const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => {
let value = formatObj[key]
// Note: getDay() returns 0 on Sunday
if (key === 'a') {
return ['日', '一', '二', '三', '四', '五', '六'][value]
}
if (result.length > 0 && value < 10) {
value = '0' + value
}
return value || 0
})
return time_str
}
/**
@ -189,5 +194,56 @@ export const dateFormatter = (row, column, cellValue) => {
if (!cellValue) {
return
}
return dayjs(cellValue).format('YYYY-MM-DD HH:mm:ss')
return formatDate(cellValue)
}
/**
* 00:00:00
* @param param
* @returns 00:00:00
*/
export function beginOfDay(param: Date) {
return new Date(param.getFullYear(), param.getMonth(), param.getDate(), 0, 0, 0, 0)
}
/**
* 23:59:59
* @param param
* @returns 23:59:59
*/
export function endOfDay(param: Date) {
return new Date(param.getFullYear(), param.getMonth(), param.getDate(), 23, 59, 59, 999)
}
/**
*
* @param param1 1
* @param param2 2
*/
export function betweenDay(param1: Date, param2: Date) {
param1 = convertDate(param1)
param2 = convertDate(param2)
// 计算差值
return Math.floor((param2.getTime() - param1.getTime()) / (24 * 3600 * 1000))
}
/**
*
* @param param1
* @param param2
*/
export function addTime(param1: Date, param2: number) {
param1 = convertDate(param1)
return new Date(param1.getTime() + param2)
}
/**
*
* @param param
*/
export function convertDate(param: Date | string) {
if (typeof param === 'string') {
return new Date(param)
}
return param
}

View File

@ -137,3 +137,21 @@ export const generateUUID = () => {
return (c === 'x' ? random : (random & 0x3) | 0x8).toString(16)
})
}
/**
* element plus Formatter
*
* @param row
* @param column
* @param cellValue
*/
// @ts-ignore
export const fileSizeFormatter = (row, column, cellValue) => {
const fileSize = cellValue
const unitArr = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
const srcSize = parseFloat(fileSize)
const index = Math.floor(Math.log(srcSize) / Math.log(1024))
const size = srcSize / Math.pow(1024, index)
const sizeStr = size.toFixed(2) //保留的小数位数
return sizeStr + ' ' + unitArr[index]
}

View File

@ -276,7 +276,7 @@ export const handleTree = (data: any[], id?: string, parentId?: string, children
export const handleTree2 = (data, id, parentId, children, rootId) => {
id = id || 'id'
parentId = parentId || 'parentId'
children = children || 'children'
// children = children || 'children'
rootId =
rootId ||
Math.min(
@ -285,16 +285,16 @@ export const handleTree2 = (data, id, parentId, children, rootId) => {
})
) ||
0
//对源数据深度克隆
// 对源数据深度克隆
const cloneData = JSON.parse(JSON.stringify(data))
//循环所有项
// 循环所有项
const treeData = cloneData.filter((father) => {
const branchArr = cloneData.filter((child) => {
//返回每一项的子级数组
// 返回每一项的子级数组
return father[id] === child[parentId]
})
branchArr.length > 0 ? (father.children = branchArr) : ''
//返回第一层
// 返回第一层
return father[parentId] === rootId
})
return treeData !== '' ? treeData : data

View File

@ -34,13 +34,13 @@
</li>
<li class="list-group-item">
<Icon icon="ep:calendar" class="mr-5px" />{{ t('profile.user.createTime') }}
<div class="pull-right">{{ dayjs(userInfo?.createTime).format('YYYY-MM-DD') }}</div>
<div class="pull-right">{{ parseTime(userInfo?.createTime) }}</div>
</li>
</ul>
</div>
</template>
<script setup lang="ts">
import dayjs from 'dayjs'
import { parseTime } from '@/utils/formatTime'
import UserAvatar from './UserAvatar.vue'
import { getUserProfileApi, ProfileVO } from '@/api/system/user/profile'

View File

@ -44,7 +44,7 @@
<li v-for="item in getList" class="mt-2" :key="item.time">
<div class="flex items-center">
<span class="mr-2 text-primary font-medium">收到消息:</span>
<span>{{ dayjs(item.time).format('YYYY-MM-DD HH:mm:ss') }}</span>
<span>{{ parseTime(item.time) }}</span>
</div>
<div>
{{ item.res }}
@ -56,7 +56,7 @@
</div>
</template>
<script setup lang="ts">
import dayjs from 'dayjs'
import { parseTime } from '@/utils/formatTime'
import { useUserStore } from '@/store/modules/user'
import { useWebSocket } from '@vueuse/core'

View File

@ -32,6 +32,7 @@
"vite-plugin-svg-icons/client",
"@form-create/element-ui/types"
],
"outDir": "target", // tsconfig.json
"typeRoots": ["./node_modules/@types/", "./types"]
},
"include": [
@ -40,5 +41,5 @@
"src/types/auto-imports.d.ts",
"src/types/auto-components.d.ts"
],
"exclude": ["dist", "node_modules"]
"exclude": ["dist", "target", "node_modules"]
}

View File

@ -1,6 +1,7 @@
declare module 'vue' {
export interface GlobalComponents {
Icon: typeof import('../components/Icon/src/Icon.vue')['default']
Icon: typeof import('@/components/Icon')['Icon']
DictTag: typeof import('@/components/DictTag')['DictTag']
}
}

26
types/global.d.ts vendored
View File

@ -1,29 +1,29 @@
export {}
declare global {
declare interface Fn<T = any> {
interface Fn<T = any> {
(...arg: T[]): T
}
declare type Nullable<T> = T | null
type Nullable<T> = T | null
declare type ElRef<T extends HTMLElement = HTMLDivElement> = Nullable<T>
type ElRef<T extends HTMLElement = HTMLDivElement> = Nullable<T>
declare type Recordable<T = any, K = string> = Record<K extends null | undefined ? string : K, T>
type Recordable<T = any, K = string> = Record<K extends null | undefined ? string : K, T>
declare type ComponentRef<T> = InstanceType<T>
type ComponentRef<T> = InstanceType<T>
declare type LocaleType = 'zh-CN' | 'en'
type LocaleType = 'zh-CN' | 'en'
declare type AxiosHeaders =
type AxiosHeaders =
| 'application/json'
| 'application/x-www-form-urlencoded'
| 'multipart/form-data'
declare type AxiosMethod = 'get' | 'post' | 'delete' | 'put' | 'GET' | 'POST' | 'DELETE' | 'PUT'
type AxiosMethod = 'get' | 'post' | 'delete' | 'put' | 'GET' | 'POST' | 'DELETE' | 'PUT'
declare type AxiosResponseType = 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream'
type AxiosResponseType = 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream'
declare interface AxiosConfig {
interface AxiosConfig {
params?: any
data?: any
url?: string
@ -32,17 +32,17 @@ declare global {
responseType?: AxiosResponseType
}
declare interface IResponse<T = any> {
interface IResponse<T = any> {
code: string
data: T extends any ? T : T & any
}
declare interface PageParam {
interface PageParam {
pageSize?: number
pageNo?: number
}
declare interface Tree {
interface Tree {
id: number
name: string
children?: Tree[] | any[]

4
types/router.d.ts vendored
View File

@ -54,7 +54,7 @@ type Component<T = any> =
| (() => Promise<T>)
declare global {
declare interface AppRouteRecordRaw extends Omit<RouteRecordRaw, 'meta'> {
interface AppRouteRecordRaw extends Omit<RouteRecordRaw, 'meta'> {
name: string
meta: RouteMeta
component?: Component | string
@ -64,7 +64,7 @@ declare global {
keepAlive?: boolean
}
declare interface AppCustomRouteRecordRaw extends Omit<RouteRecordRaw, 'meta'> {
interface AppCustomRouteRecordRaw extends Omit<RouteRecordRaw, 'meta'> {
icon: any
name: string
meta: RouteMeta

View File

@ -42,7 +42,7 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
// },
},
// 项目使用的vite插件。 单独提取到build/vite/plugin中管理
plugins: createVitePlugins(env.VITE_APP_TITLE),
plugins: createVitePlugins(),
css: {
preprocessorOptions: {
scss: {