mirror of
https://github.com/jekip/naive-ui-admin.git
synced 2026-02-11 08:42:28 +08:00
fix Bug or esLink formatting
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<n-dialog-provider>
|
||||
<DialogContent/>
|
||||
<DialogContent />
|
||||
<n-notification-provider>
|
||||
<n-message-provider>
|
||||
<MessageContent/>
|
||||
<MessageContent />
|
||||
<slot slot="default"></slot>
|
||||
</n-message-provider>
|
||||
</n-notification-provider>
|
||||
@@ -11,15 +11,15 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { MessageContent } from '@/components/MessageContent'
|
||||
import { DialogContent } from '@/components/DialogContent'
|
||||
import { defineComponent } from 'vue';
|
||||
import { MessageContent } from '@/components/MessageContent';
|
||||
import { DialogContent } from '@/components/DialogContent';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Application',
|
||||
components: { MessageContent, DialogContent },
|
||||
setup() {
|
||||
return {}
|
||||
}
|
||||
})
|
||||
export default defineComponent({
|
||||
name: 'Application',
|
||||
components: { MessageContent, DialogContent },
|
||||
setup() {
|
||||
return {};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import AppProvider from './Application.vue'
|
||||
import AppProvider from './Application.vue';
|
||||
|
||||
export { AppProvider }
|
||||
export { AppProvider };
|
||||
|
||||
@@ -4,107 +4,107 @@
|
||||
</span>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, computed, watchEffect, unref, onMounted, watch } from 'vue';
|
||||
import { useTransition, TransitionPresets } from '@vueuse/core';
|
||||
import { isNumber } from '@/utils/is';
|
||||
import { defineComponent, ref, computed, watchEffect, unref, onMounted, watch } from 'vue';
|
||||
import { useTransition, TransitionPresets } from '@vueuse/core';
|
||||
import { isNumber } from '@/utils/is';
|
||||
|
||||
const props = {
|
||||
startVal: { type: Number, default: 0 },
|
||||
endVal: { type: Number, default: 2021 },
|
||||
duration: { type: Number, default: 1500 },
|
||||
autoplay: { type: Boolean, default: true },
|
||||
decimals: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
validator(value: number) {
|
||||
return value >= 0;
|
||||
const props = {
|
||||
startVal: { type: Number, default: 0 },
|
||||
endVal: { type: Number, default: 2021 },
|
||||
duration: { type: Number, default: 1500 },
|
||||
autoplay: { type: Boolean, default: true },
|
||||
decimals: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
validator(value: number) {
|
||||
return value >= 0;
|
||||
},
|
||||
},
|
||||
},
|
||||
prefix: { type: String, default: '' },
|
||||
suffix: { type: String, default: '' },
|
||||
separator: { type: String, default: ',' },
|
||||
decimal: { type: String, default: '.' },
|
||||
/**
|
||||
* font color
|
||||
*/
|
||||
color: { type: String },
|
||||
/**
|
||||
* Turn on digital animation
|
||||
*/
|
||||
useEasing: { type: Boolean, default: true },
|
||||
/**
|
||||
* Digital animation
|
||||
*/
|
||||
transition: { type: String, default: 'linear' },
|
||||
};
|
||||
prefix: { type: String, default: '' },
|
||||
suffix: { type: String, default: '' },
|
||||
separator: { type: String, default: ',' },
|
||||
decimal: { type: String, default: '.' },
|
||||
/**
|
||||
* font color
|
||||
*/
|
||||
color: { type: String },
|
||||
/**
|
||||
* Turn on digital animation
|
||||
*/
|
||||
useEasing: { type: Boolean, default: true },
|
||||
/**
|
||||
* Digital animation
|
||||
*/
|
||||
transition: { type: String, default: 'linear' },
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
name: 'CountTo',
|
||||
props,
|
||||
emits: ['onStarted', 'onFinished'],
|
||||
setup(props, { emit }) {
|
||||
const source = ref(props.startVal);
|
||||
const disabled = ref(false);
|
||||
let outputValue = useTransition(source);
|
||||
export default defineComponent({
|
||||
name: 'CountTo',
|
||||
props,
|
||||
emits: ['onStarted', 'onFinished'],
|
||||
setup(props, { emit }) {
|
||||
const source = ref(props.startVal);
|
||||
const disabled = ref(false);
|
||||
let outputValue = useTransition(source);
|
||||
|
||||
const value = computed(() => formatNumber(unref(outputValue)));
|
||||
const value = computed(() => formatNumber(unref(outputValue)));
|
||||
|
||||
watchEffect(() => {
|
||||
source.value = props.startVal;
|
||||
});
|
||||
|
||||
watch([() => props.startVal, () => props.endVal], () => {
|
||||
if (props.autoplay) {
|
||||
start();
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
props.autoplay && start();
|
||||
});
|
||||
|
||||
function start() {
|
||||
run();
|
||||
source.value = props.endVal;
|
||||
}
|
||||
|
||||
function reset() {
|
||||
source.value = props.startVal;
|
||||
run();
|
||||
}
|
||||
|
||||
function run() {
|
||||
outputValue = useTransition(source, {
|
||||
disabled,
|
||||
duration: props.duration,
|
||||
onFinished: () => emit('onFinished'),
|
||||
onStarted: () => emit('onStarted'),
|
||||
...(props.useEasing ? { transition: TransitionPresets[props.transition] } : {}),
|
||||
watchEffect(() => {
|
||||
source.value = props.startVal;
|
||||
});
|
||||
}
|
||||
|
||||
function formatNumber(num: number | string) {
|
||||
if (!num) {
|
||||
return '';
|
||||
}
|
||||
const { decimals, decimal, separator, suffix, prefix } = props;
|
||||
num = Number(num).toFixed(decimals);
|
||||
num += '';
|
||||
|
||||
const x = num.split('.');
|
||||
let x1 = x[0];
|
||||
const x2 = x.length > 1 ? decimal + x[1] : '';
|
||||
|
||||
const rgx = /(\d+)(\d{3})/;
|
||||
if (separator && !isNumber(separator)) {
|
||||
while (rgx.test(x1)) {
|
||||
x1 = x1.replace(rgx, '$1' + separator + '$2');
|
||||
watch([() => props.startVal, () => props.endVal], () => {
|
||||
if (props.autoplay) {
|
||||
start();
|
||||
}
|
||||
}
|
||||
return prefix + x1 + x2 + suffix;
|
||||
}
|
||||
});
|
||||
|
||||
return { value, start, reset };
|
||||
},
|
||||
});
|
||||
onMounted(() => {
|
||||
props.autoplay && start();
|
||||
});
|
||||
|
||||
function start() {
|
||||
run();
|
||||
source.value = props.endVal;
|
||||
}
|
||||
|
||||
function reset() {
|
||||
source.value = props.startVal;
|
||||
run();
|
||||
}
|
||||
|
||||
function run() {
|
||||
outputValue = useTransition(source, {
|
||||
disabled,
|
||||
duration: props.duration,
|
||||
onFinished: () => emit('onFinished'),
|
||||
onStarted: () => emit('onStarted'),
|
||||
...(props.useEasing ? { transition: TransitionPresets[props.transition] } : {}),
|
||||
});
|
||||
}
|
||||
|
||||
function formatNumber(num: number | string) {
|
||||
if (!num) {
|
||||
return '';
|
||||
}
|
||||
const { decimals, decimal, separator, suffix, prefix } = props;
|
||||
num = Number(num).toFixed(decimals);
|
||||
num += '';
|
||||
|
||||
const x = num.split('.');
|
||||
let x1 = x[0];
|
||||
const x2 = x.length > 1 ? decimal + x[1] : '';
|
||||
|
||||
const rgx = /(\d+)(\d{3})/;
|
||||
if (separator && !isNumber(separator)) {
|
||||
while (rgx.test(x1)) {
|
||||
x1 = x1.replace(rgx, '$1' + separator + '$2');
|
||||
}
|
||||
}
|
||||
return prefix + x1 + x2 + suffix;
|
||||
}
|
||||
|
||||
return { value, start, reset };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import DialogContent from './index.vue'
|
||||
import DialogContent from './index.vue';
|
||||
|
||||
export { DialogContent }
|
||||
export { DialogContent };
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<template></template>
|
||||
<script lang="ts">
|
||||
import { useDialog } from 'naive-ui'
|
||||
import { useDialog } from 'naive-ui';
|
||||
|
||||
export default {
|
||||
name: 'DialogContent',
|
||||
setup() {
|
||||
//挂载在 window 方便与在js中使用
|
||||
window.$dialog = useDialog()
|
||||
}
|
||||
}
|
||||
export default {
|
||||
name: 'DialogContent',
|
||||
setup() {
|
||||
//挂载在 window 方便与在js中使用
|
||||
window['$dialog'] = useDialog();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,29 +1,27 @@
|
||||
<template>
|
||||
<div
|
||||
:class="{ onLockLogin: showLogin }"
|
||||
class="lockscreen"
|
||||
@keyup="onLockLogin(true)"
|
||||
@mousedown.stop
|
||||
@contextmenu.prevent
|
||||
:class="{ onLockLogin: showLogin }"
|
||||
class="lockscreen"
|
||||
@keyup="onLockLogin(true)"
|
||||
@mousedown.stop
|
||||
@contextmenu.prevent
|
||||
>
|
||||
<template v-if="!showLogin">
|
||||
|
||||
<div class="lock-box">
|
||||
<div class="lock">
|
||||
<span class="lock-icon" title="解锁屏幕" @click="onLockLogin(true)">
|
||||
<n-icon>
|
||||
<lock-outlined/>
|
||||
<lock-outlined />
|
||||
</n-icon>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!--充电-->
|
||||
<recharge
|
||||
:battery="battery"
|
||||
:battery-status="batteryStatus"
|
||||
:calc-discharging-time="calcDischargingTime"
|
||||
></recharge>
|
||||
:battery="battery"
|
||||
:battery-status="batteryStatus"
|
||||
:calc-discharging-time="calcDischargingTime"
|
||||
/>
|
||||
|
||||
<div class="local-time">
|
||||
<div class="time">{{ hour }}:{{ minute }}</div>
|
||||
@@ -31,9 +29,9 @@
|
||||
</div>
|
||||
<div class="computer-status">
|
||||
<span :class="{ offline: !online }" class="network">
|
||||
<wifi-outlined class="network"/>
|
||||
<wifi-outlined class="network" />
|
||||
</span>
|
||||
<api-outlined/>
|
||||
<api-outlined />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -42,19 +40,20 @@
|
||||
<div class="login-box">
|
||||
<n-avatar :size="128">
|
||||
<n-icon>
|
||||
<user-outlined/>
|
||||
<user-outlined />
|
||||
</n-icon>
|
||||
</n-avatar>
|
||||
<div class="username">{{ loginParams.username }}</div>
|
||||
<n-input
|
||||
type="password"
|
||||
autofocus
|
||||
v-model:value="loginParams.password"
|
||||
placeholder="请输入登录密码">
|
||||
type="password"
|
||||
autofocus
|
||||
v-model:value="loginParams.password"
|
||||
placeholder="请输入登录密码"
|
||||
>
|
||||
<template #suffix>
|
||||
<n-icon @click="onLogin" style="cursor: pointer;">
|
||||
<LoadingOutlined v-if="loginLoading"/>
|
||||
<arrow-right-outlined v-else/>
|
||||
<n-icon @click="onLogin" style="cursor: pointer">
|
||||
<LoadingOutlined v-if="loginLoading" />
|
||||
<arrow-right-outlined v-else />
|
||||
</n-icon>
|
||||
</template>
|
||||
</n-input>
|
||||
@@ -64,241 +63,239 @@
|
||||
</div>
|
||||
|
||||
<div class="w-full mt-1 flex justify-around">
|
||||
<div><a @click="showLogin=false">返回</a></div>
|
||||
<div><a @click="showLogin = false">返回</a></div>
|
||||
<div><a @click="goLogin">重新登录</a></div>
|
||||
<div><a @click="onLogin">进入系统</a></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, reactive, toRefs, computed } from 'vue'
|
||||
import { ResultEnum } from '@/enums/httpEnum'
|
||||
import recharge from './Recharge.vue'
|
||||
import {
|
||||
LockOutlined,
|
||||
LoadingOutlined,
|
||||
UnlockOutlined,
|
||||
UserOutlined,
|
||||
ApiOutlined,
|
||||
ArrowRightOutlined,
|
||||
WifiOutlined,
|
||||
} from '@vicons/antd'
|
||||
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { useOnline } from '@/hooks/useOnline'
|
||||
import { useTime } from '@/hooks/useTime'
|
||||
import { useBattery } from '@/hooks/useBattery'
|
||||
import { useLockscreenStore } from '@/store/modules/lockscreen'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Lockscreen',
|
||||
components: {
|
||||
import { defineComponent, reactive, toRefs } from 'vue';
|
||||
import { ResultEnum } from '@/enums/httpEnum';
|
||||
import recharge from './Recharge.vue';
|
||||
import {
|
||||
LockOutlined,
|
||||
LoadingOutlined,
|
||||
UnlockOutlined,
|
||||
UserOutlined,
|
||||
ArrowRightOutlined,
|
||||
ApiOutlined,
|
||||
ArrowRightOutlined,
|
||||
WifiOutlined,
|
||||
recharge,
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const useLockscreen = useLockscreenStore()
|
||||
const userStore = useUserStore();
|
||||
} from '@vicons/antd';
|
||||
|
||||
// 获取时间
|
||||
const { month, day, hour, minute, second, week } = useTime()
|
||||
const { online } = useOnline()
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { useOnline } from '@/hooks/useOnline';
|
||||
import { useTime } from '@/hooks/useTime';
|
||||
import { useBattery } from '@/hooks/useBattery';
|
||||
import { useLockscreenStore } from '@/store/modules/lockscreen';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
export default defineComponent({
|
||||
name: 'Lockscreen',
|
||||
components: {
|
||||
LockOutlined,
|
||||
LoadingOutlined,
|
||||
UserOutlined,
|
||||
ArrowRightOutlined,
|
||||
ApiOutlined,
|
||||
WifiOutlined,
|
||||
recharge,
|
||||
},
|
||||
setup() {
|
||||
const useLockscreen = useLockscreenStore();
|
||||
const userStore = useUserStore();
|
||||
|
||||
const { battery, batteryStatus, calcDischargingTime } = useBattery()
|
||||
const { username } = userStore.getUserInfo || {}
|
||||
const state = reactive({
|
||||
showLogin: false,
|
||||
loginLoading: false, // 正在登录
|
||||
isLoginError: false, //密码错误
|
||||
errorMsg: '密码错误',
|
||||
loginParams: {
|
||||
username: username || '',
|
||||
password: ''
|
||||
}
|
||||
})
|
||||
// 获取时间
|
||||
const { month, day, hour, minute, second, week } = useTime();
|
||||
const { online } = useOnline();
|
||||
|
||||
// 解锁登录
|
||||
const onLockLogin = (value: boolean) => (state.showLogin = value)
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
// 登录
|
||||
const onLogin = async () => {
|
||||
if (!state.loginParams.password.trim()) {
|
||||
return
|
||||
}
|
||||
const params = {
|
||||
isLock: true,
|
||||
...state.loginParams
|
||||
}
|
||||
state.loginLoading = true
|
||||
const { code, result, message } = await userStore.login(params)
|
||||
if (code === ResultEnum.SUCCESS) {
|
||||
onLockLogin(false)
|
||||
useLockscreen.setLock(false)
|
||||
} else {
|
||||
state.errorMsg = message
|
||||
state.isLoginError = true
|
||||
}
|
||||
state.loginLoading = false
|
||||
}
|
||||
const { battery, batteryStatus, calcDischargingTime } = useBattery();
|
||||
const userInfo: object = userStore.getUserInfo || {};
|
||||
const username = userInfo['username'] || '';
|
||||
const state = reactive({
|
||||
showLogin: false,
|
||||
loginLoading: false, // 正在登录
|
||||
isLoginError: false, //密码错误
|
||||
errorMsg: '密码错误',
|
||||
loginParams: {
|
||||
username: username || '',
|
||||
password: '',
|
||||
},
|
||||
});
|
||||
|
||||
//重新登录
|
||||
const goLogin = () => {
|
||||
onLockLogin(false)
|
||||
useLockscreen.setLock(false)
|
||||
router.replace({
|
||||
path: '/login',
|
||||
query: {
|
||||
redirect: route.fullPath
|
||||
// 解锁登录
|
||||
const onLockLogin = (value: boolean) => (state.showLogin = value);
|
||||
|
||||
// 登录
|
||||
const onLogin = async () => {
|
||||
if (!state.loginParams.password.trim()) {
|
||||
return;
|
||||
}
|
||||
})
|
||||
}
|
||||
const params = {
|
||||
isLock: true,
|
||||
...state.loginParams,
|
||||
};
|
||||
state.loginLoading = true;
|
||||
const { code, message } = await userStore.login(params);
|
||||
if (code === ResultEnum.SUCCESS) {
|
||||
onLockLogin(false);
|
||||
useLockscreen.setLock(false);
|
||||
} else {
|
||||
state.errorMsg = message;
|
||||
state.isLoginError = true;
|
||||
}
|
||||
state.loginLoading = false;
|
||||
};
|
||||
|
||||
return {
|
||||
...toRefs(state),
|
||||
online,
|
||||
month,
|
||||
day,
|
||||
hour,
|
||||
minute,
|
||||
second,
|
||||
week,
|
||||
battery,
|
||||
batteryStatus,
|
||||
calcDischargingTime,
|
||||
onLockLogin,
|
||||
onLogin,
|
||||
goLogin
|
||||
}
|
||||
}
|
||||
})
|
||||
//重新登录
|
||||
const goLogin = () => {
|
||||
onLockLogin(false);
|
||||
useLockscreen.setLock(false);
|
||||
router.replace({
|
||||
path: '/login',
|
||||
query: {
|
||||
redirect: route.fullPath,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
...toRefs(state),
|
||||
online,
|
||||
month,
|
||||
day,
|
||||
hour,
|
||||
minute,
|
||||
second,
|
||||
week,
|
||||
battery,
|
||||
batteryStatus,
|
||||
calcDischargingTime,
|
||||
onLockLogin,
|
||||
onLogin,
|
||||
goLogin,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.lockscreen {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
background: #000;
|
||||
color: white;
|
||||
overflow: hidden;
|
||||
z-index: 9999;
|
||||
|
||||
&.onLockLogin {
|
||||
background-color: rgba(25, 28, 34, 0.88);
|
||||
backdrop-filter: blur(7px);
|
||||
}
|
||||
|
||||
.login-box {
|
||||
position: absolute;
|
||||
top: 45%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
.lockscreen {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: #000;
|
||||
color: white;
|
||||
overflow: hidden;
|
||||
z-index: 9999;
|
||||
|
||||
> * {
|
||||
margin-bottom: 14px;
|
||||
&.onLockLogin {
|
||||
background-color: rgba(25, 28, 34, 0.88);
|
||||
backdrop-filter: blur(7px);
|
||||
}
|
||||
|
||||
.username {
|
||||
font-size: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.lock-box {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
font-size: 34px;
|
||||
z-index: 100;
|
||||
|
||||
.tips {
|
||||
color: white;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.lock {
|
||||
.login-box {
|
||||
position: absolute;
|
||||
top: 45%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.lock-icon {
|
||||
cursor: pointer;
|
||||
> * {
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.anticon-unlock {
|
||||
display: none;
|
||||
.username {
|
||||
font-size: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.lock-box {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
font-size: 34px;
|
||||
z-index: 100;
|
||||
|
||||
.tips {
|
||||
color: white;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.lock {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.lock-icon {
|
||||
cursor: pointer;
|
||||
|
||||
.anticon-unlock {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover .anticon-unlock {
|
||||
display: initial;
|
||||
}
|
||||
|
||||
&:hover .anticon-lock {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .anticon-unlock {
|
||||
display: initial;
|
||||
}
|
||||
.local-time {
|
||||
position: absolute;
|
||||
bottom: 60px;
|
||||
left: 60px;
|
||||
font-family: helvetica;
|
||||
|
||||
&:hover .anticon-lock {
|
||||
display: none;
|
||||
.time {
|
||||
font-size: 70px;
|
||||
}
|
||||
|
||||
.date {
|
||||
font-size: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.computer-status {
|
||||
position: absolute;
|
||||
bottom: 60px;
|
||||
right: 60px;
|
||||
font-size: 24px;
|
||||
|
||||
> * {
|
||||
margin-left: 14px;
|
||||
}
|
||||
|
||||
.network {
|
||||
position: relative;
|
||||
|
||||
&.offline::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
width: 2px;
|
||||
height: 28px;
|
||||
transform: translate(-50%, -50%) rotate(45deg);
|
||||
background-color: red;
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.local-time {
|
||||
position: absolute;
|
||||
bottom: 60px;
|
||||
left: 60px;
|
||||
font-family: helvetica;
|
||||
|
||||
.time {
|
||||
font-size: 70px;
|
||||
}
|
||||
|
||||
.date {
|
||||
font-size: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.computer-status {
|
||||
position: absolute;
|
||||
bottom: 60px;
|
||||
right: 60px;
|
||||
font-size: 24px;
|
||||
|
||||
> * {
|
||||
margin-left: 14px;
|
||||
}
|
||||
|
||||
.network {
|
||||
position: relative;
|
||||
|
||||
&.offline::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
width: 2px;
|
||||
height: 28px;
|
||||
transform: translate(-50%, -50%) rotate(45deg);
|
||||
background-color: red;
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -20,120 +20,120 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'HuaweiCharge',
|
||||
// props: ['batteryStatus', 'battery', 'calcDischargingTime'],
|
||||
props: {
|
||||
battery: {
|
||||
// 电池对象
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
export default defineComponent({
|
||||
name: 'HuaweiCharge',
|
||||
// props: ['batteryStatus', 'battery', 'calcDischargingTime'],
|
||||
props: {
|
||||
battery: {
|
||||
// 电池对象
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
calcDischargingTime: {
|
||||
// 电池剩余时间可用时间
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
batteryStatus: {
|
||||
// 电池状态
|
||||
type: String,
|
||||
validator: (val: string) => ['充电中', '已充满', '已断开电源'].includes(val),
|
||||
},
|
||||
},
|
||||
calcDischargingTime: {
|
||||
// 电池剩余时间可用时间
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
batteryStatus: {
|
||||
// 电池状态
|
||||
type: String,
|
||||
validator: (val: string) => ['充电中', '已充满', '已断开电源'].includes(val)
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.container {
|
||||
position: absolute;
|
||||
bottom: 20vh;
|
||||
left: 50vw;
|
||||
width: 300px;
|
||||
height: 400px;
|
||||
transform: translateX(-50%);
|
||||
|
||||
.number {
|
||||
.container {
|
||||
position: absolute;
|
||||
top: 27%;
|
||||
z-index: 10;
|
||||
width: 300px;
|
||||
font-size: 32px;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.contrast {
|
||||
bottom: 20vh;
|
||||
left: 50vw;
|
||||
width: 300px;
|
||||
height: 400px;
|
||||
overflow: hidden;
|
||||
background-color: #000;
|
||||
filter: contrast(15) hue-rotate(0);
|
||||
animation: hueRotate 10s infinite linear;
|
||||
transform: translateX(-50%);
|
||||
|
||||
.circle {
|
||||
position: relative;
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
filter: blur(8px);
|
||||
box-sizing: border-box;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
top: 40%;
|
||||
left: 50%;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
background-color: #00ff6f;
|
||||
border-radius: 42% 38% 62% 49% / 45%;
|
||||
content: '';
|
||||
transform: translate(-50%, -50%) rotate(0);
|
||||
animation: rotate 10s infinite linear;
|
||||
}
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: 40%;
|
||||
left: 50%;
|
||||
z-index: 10;
|
||||
width: 176px;
|
||||
height: 176px;
|
||||
background-color: #000;
|
||||
border-radius: 50%;
|
||||
content: '';
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
}
|
||||
|
||||
.bubbles {
|
||||
.number {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
background-color: #00ff6f;
|
||||
border-radius: 100px 100px 0 0;
|
||||
filter: blur(5px);
|
||||
transform: translate(-50%, 0);
|
||||
top: 27%;
|
||||
z-index: 10;
|
||||
width: 300px;
|
||||
font-size: 32px;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
li {
|
||||
position: absolute;
|
||||
background: #00ff6f;
|
||||
border-radius: 50%;
|
||||
.contrast {
|
||||
width: 300px;
|
||||
height: 400px;
|
||||
overflow: hidden;
|
||||
background-color: #000;
|
||||
filter: contrast(15) hue-rotate(0);
|
||||
animation: hueRotate 10s infinite linear;
|
||||
|
||||
.circle {
|
||||
position: relative;
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
filter: blur(8px);
|
||||
box-sizing: border-box;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
top: 40%;
|
||||
left: 50%;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
background-color: #00ff6f;
|
||||
border-radius: 42% 38% 62% 49% / 45%;
|
||||
content: '';
|
||||
transform: translate(-50%, -50%) rotate(0);
|
||||
animation: rotate 10s infinite linear;
|
||||
}
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: 40%;
|
||||
left: 50%;
|
||||
z-index: 10;
|
||||
width: 176px;
|
||||
height: 176px;
|
||||
background-color: #000;
|
||||
border-radius: 50%;
|
||||
content: '';
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
}
|
||||
|
||||
.bubbles {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
background-color: #00ff6f;
|
||||
border-radius: 100px 100px 0 0;
|
||||
filter: blur(5px);
|
||||
transform: translate(-50%, 0);
|
||||
|
||||
li {
|
||||
position: absolute;
|
||||
background: #00ff6f;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.charging {
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.charging {
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
@width: ~`Math.round(Math.random() * 100)` px;
|
||||
@left: calc(15px + `Math.round(Math.random(70))`);
|
||||
each(range(15), {
|
||||
@width: ~`Math.round(Math.random() * 100) ` px;
|
||||
@left: calc(15px + `Math.round(Math.random(70)) `);
|
||||
each(range(15), {
|
||||
.xiaoma-@{value} {
|
||||
height: (@value * 50px);
|
||||
}
|
||||
@@ -147,31 +147,30 @@ each(range(15), {
|
||||
}
|
||||
});
|
||||
|
||||
@keyframes rotate {
|
||||
50% {
|
||||
border-radius: 45% / 42% 38% 58% 49%;
|
||||
}
|
||||
|
||||
@keyframes rotate {
|
||||
50% {
|
||||
border-radius: 45% / 42% 38% 58% 49%;
|
||||
100% {
|
||||
transform: translate(-50%, -50%) rotate(720deg);
|
||||
}
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translate(-50%, -50%) rotate(720deg);
|
||||
}
|
||||
}
|
||||
@keyframes moveToTop {
|
||||
90% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@keyframes moveToTop {
|
||||
90% {
|
||||
opacity: 1;
|
||||
100% {
|
||||
opacity: 0.1;
|
||||
transform: translate(-50%, -180px);
|
||||
}
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0.1;
|
||||
transform: translate(-50%, -180px);
|
||||
@keyframes hueRotate {
|
||||
100% {
|
||||
filter: contrast(15) hue-rotate(360deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes hueRotate {
|
||||
100% {
|
||||
filter: contrast(15) hue-rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import LockScreen from './Lockscreen.vue'
|
||||
import LockScreen from './Lockscreen.vue';
|
||||
|
||||
export { LockScreen }
|
||||
export { LockScreen };
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import MessageContent from './index.vue'
|
||||
import MessageContent from './index.vue';
|
||||
|
||||
export { MessageContent }
|
||||
export { MessageContent };
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<template></template>
|
||||
<script lang="ts">
|
||||
import { useMessage } from 'naive-ui'
|
||||
import { useMessage } from 'naive-ui';
|
||||
|
||||
export default {
|
||||
name: 'MessageContent',
|
||||
setup() {
|
||||
//挂载在 window 方便与在js中使用
|
||||
window.$message = useMessage()
|
||||
}
|
||||
}
|
||||
export default {
|
||||
name: 'MessageContent',
|
||||
setup() {
|
||||
//挂载在 window 方便与在js中使用
|
||||
window['$message'] = useMessage();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -2,4 +2,3 @@ export { default as BasicTable } from './src/Table.vue';
|
||||
export { default as TableAction } from './src/components/TableAction.vue';
|
||||
export * from './src/types/table';
|
||||
export * from './src/types/tableAction';
|
||||
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
<template>
|
||||
<div class="table-toolbar">
|
||||
|
||||
<!--顶部左侧区域-->
|
||||
<div class="flex items-center table-toolbar-left ">
|
||||
<div class="flex items-center table-toolbar-left">
|
||||
<template v-if="title">
|
||||
<div class="table-toolbar-left-title">
|
||||
{{ title }}
|
||||
<n-tooltip trigger="hover" v-if="titleTooltip">
|
||||
<template #trigger>
|
||||
<n-icon size="18" class="ml-1 cursor-pointer text-gray-400">
|
||||
<QuestionCircleOutlined/>
|
||||
<QuestionCircleOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
{{ titleTooltip }}
|
||||
@@ -20,7 +19,6 @@
|
||||
</div>
|
||||
|
||||
<div class="flex items-center table-toolbar-right">
|
||||
|
||||
<!--顶部右侧区域-->
|
||||
<slot name="toolbar"></slot>
|
||||
|
||||
@@ -29,7 +27,7 @@
|
||||
<template #trigger>
|
||||
<div class="table-toolbar-right-icon" @click="reload">
|
||||
<n-icon size="18">
|
||||
<ReloadOutlined/>
|
||||
<ReloadOutlined />
|
||||
</n-icon>
|
||||
</div>
|
||||
</template>
|
||||
@@ -40,9 +38,14 @@
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<div class="table-toolbar-right-icon">
|
||||
<n-dropdown @select="densitySelect" trigger="click" :options="densityOptions" v-model:value="tableSize">
|
||||
<n-dropdown
|
||||
@select="densitySelect"
|
||||
trigger="click"
|
||||
:options="densityOptions"
|
||||
v-model:value="tableSize"
|
||||
>
|
||||
<n-icon size="18">
|
||||
<ColumnHeightOutlined/>
|
||||
<ColumnHeightOutlined />
|
||||
</n-icon>
|
||||
</n-dropdown>
|
||||
</div>
|
||||
@@ -51,17 +54,15 @@
|
||||
</n-tooltip>
|
||||
|
||||
<!--表格设置单独抽离成组件-->
|
||||
<ColumnSetting></ColumnSetting>
|
||||
|
||||
<ColumnSetting />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="s-table">
|
||||
<n-data-table
|
||||
v-bind="getBindValues"
|
||||
:pagination="pagination"
|
||||
@update:page="updatePage"
|
||||
@update:page-size="updatePageSize"
|
||||
v-bind="getBindValues"
|
||||
:pagination="pagination"
|
||||
@update:page="updatePage"
|
||||
@update:page-size="updatePageSize"
|
||||
>
|
||||
<template #[item]="data" v-for="item in Object.keys($slots)" :key="item">
|
||||
<slot :name="item" v-bind="data"></slot>
|
||||
@@ -71,226 +72,212 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { NDataTable } from 'naive-ui'
|
||||
import { ref, defineComponent, reactive, unref, onMounted, toRaw, onBeforeMount, computed, toRefs, watch } from "vue"
|
||||
import { ReloadOutlined, ColumnHeightOutlined, SettingOutlined, DragOutlined, QuestionCircleOutlined } from '@vicons/antd'
|
||||
import { createTableContext } from './hooks/useTableContext';
|
||||
import { NDataTable } from 'naive-ui';
|
||||
import { ref, defineComponent, reactive, unref, toRaw, computed, toRefs } from 'vue';
|
||||
import { ReloadOutlined, ColumnHeightOutlined, QuestionCircleOutlined } from '@vicons/antd';
|
||||
import { createTableContext } from './hooks/useTableContext';
|
||||
|
||||
import ColumnSetting from './components/settings/ColumnSetting.vue'
|
||||
import ColumnSetting from './components/settings/ColumnSetting.vue';
|
||||
|
||||
import { useLoading } from './hooks/useLoading';
|
||||
import { useColumns } from './hooks/useColumns';
|
||||
import { useDataSource } from './hooks/useDataSource';
|
||||
import { usePagination } from './hooks/usePagination';
|
||||
import { useLoading } from './hooks/useLoading';
|
||||
import { useColumns } from './hooks/useColumns';
|
||||
import { useDataSource } from './hooks/useDataSource';
|
||||
import { usePagination } from './hooks/usePagination';
|
||||
|
||||
import { basicProps } from './props'
|
||||
import { basicProps } from './props';
|
||||
|
||||
import { BasicTableProps } from './types/table'
|
||||
import { BasicTableProps } from './types/table';
|
||||
|
||||
const densityOptions = [
|
||||
{
|
||||
type: 'menu',
|
||||
label: '紧凑',
|
||||
key: 'small',
|
||||
},
|
||||
{
|
||||
type: 'menu',
|
||||
label: '默认',
|
||||
key: 'medium',
|
||||
},
|
||||
{
|
||||
type: 'menu',
|
||||
label: '宽松',
|
||||
key: 'large',
|
||||
},
|
||||
];
|
||||
|
||||
const densityOptions = [
|
||||
{
|
||||
type: "menu",
|
||||
label: '紧凑',
|
||||
key: 'small',
|
||||
},
|
||||
{
|
||||
type: "menu",
|
||||
label: '默认',
|
||||
key: "medium"
|
||||
},
|
||||
{
|
||||
type: "menu",
|
||||
label: '宽松',
|
||||
key: 'large'
|
||||
}
|
||||
]
|
||||
export default defineComponent({
|
||||
components: {
|
||||
ReloadOutlined,
|
||||
ColumnHeightOutlined,
|
||||
ColumnSetting,
|
||||
QuestionCircleOutlined,
|
||||
},
|
||||
props: {
|
||||
...NDataTable.props, // 这里继承原 UI 组件的 props
|
||||
...basicProps,
|
||||
},
|
||||
emits: ['fetch-success', 'fetch-error', 'update:checked-row-keys'],
|
||||
setup(props, { emit }) {
|
||||
const wrapRef = ref<Nullable<HTMLDivElement>>(null);
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
ReloadOutlined, ColumnHeightOutlined, SettingOutlined, DragOutlined, ColumnSetting, QuestionCircleOutlined
|
||||
},
|
||||
props: {
|
||||
...NDataTable.props, // 这里继承原 UI 组件的 props
|
||||
...basicProps
|
||||
},
|
||||
emits: [
|
||||
'fetch-success',
|
||||
'fetch-error',
|
||||
'update:checked-row-keys'
|
||||
],
|
||||
setup(props, { emit }) {
|
||||
const tableData = ref<Recordable[]>([]);
|
||||
const innerPropsRef = ref<Partial<BasicTableProps>>();
|
||||
|
||||
const wrapRef = ref<Nullable<HTMLDivElement>>(null);
|
||||
const getProps = computed(() => {
|
||||
return { ...props, ...unref(innerPropsRef) } as BasicTableProps;
|
||||
});
|
||||
|
||||
const tableData = ref<Recordable[]>([]);
|
||||
const innerPropsRef = ref<Partial<BasicTableProps>>();
|
||||
const { getLoading, setLoading } = useLoading(getProps);
|
||||
|
||||
const getProps = computed(() => {
|
||||
return { ...props, ...unref(innerPropsRef) } as BasicTableProps;
|
||||
});
|
||||
const { getPaginationInfo, setPagination } = usePagination(getProps);
|
||||
|
||||
const { getLoading, setLoading } = useLoading(getProps);
|
||||
|
||||
const {
|
||||
getPaginationInfo,
|
||||
getPagination,
|
||||
setPagination,
|
||||
setShowPagination,
|
||||
getShowPagination,
|
||||
} = usePagination(getProps)
|
||||
|
||||
const { getDataSourceRef, getRowKey, getDataSource, setDataSource, reload } = useDataSource(
|
||||
getProps, {
|
||||
const { getDataSourceRef, getRowKey, reload } = useDataSource(
|
||||
getProps,
|
||||
{
|
||||
getPaginationInfo,
|
||||
setPagination,
|
||||
tableData,
|
||||
setLoading
|
||||
}, emit
|
||||
)
|
||||
setLoading,
|
||||
},
|
||||
emit
|
||||
);
|
||||
|
||||
const {
|
||||
getPageColumns,
|
||||
setColumns,
|
||||
getColumns,
|
||||
getCacheColumns,
|
||||
setCacheColumnsField,
|
||||
getColumnsRef
|
||||
} = useColumns(getProps)
|
||||
const { getPageColumns, setColumns, getColumns, getCacheColumns, setCacheColumnsField } =
|
||||
useColumns(getProps);
|
||||
|
||||
const state = reactive({
|
||||
tableSize: 'medium',
|
||||
isColumnSetting: false
|
||||
})
|
||||
const state = reactive({
|
||||
tableSize: 'medium',
|
||||
isColumnSetting: false,
|
||||
});
|
||||
|
||||
//页码切换
|
||||
function updatePage(page) {
|
||||
setPagination({ page: page, });
|
||||
reload()
|
||||
}
|
||||
|
||||
//分页数量切换
|
||||
function updatePageSize(size) {
|
||||
setPagination({ page: 1, pageSize: size, });
|
||||
reload()
|
||||
}
|
||||
|
||||
//密度切换
|
||||
function densitySelect(e) {
|
||||
state.tableSize = e
|
||||
}
|
||||
|
||||
//选中行
|
||||
function updateCheckedRowKeys(rowKeys) {
|
||||
emit('update:checked-row-keys', rowKeys)
|
||||
}
|
||||
|
||||
//重置 Columns
|
||||
const resetColumns = () => {
|
||||
columns.map(item => {
|
||||
item.isShow = true
|
||||
})
|
||||
}
|
||||
|
||||
//获取表格大小
|
||||
const getTableSize = computed(() => state.tableSize)
|
||||
|
||||
//组装表格信息
|
||||
const getBindValues = computed(() => {
|
||||
const tableData = unref(getDataSourceRef);
|
||||
let propsData = {
|
||||
...unref(getProps),
|
||||
loading: unref(getLoading),
|
||||
columns: toRaw(unref(getPageColumns)),
|
||||
rowKey: unref(getRowKey),
|
||||
data: tableData,
|
||||
size: unref(getTableSize),
|
||||
remote: true
|
||||
//页码切换
|
||||
function updatePage(page) {
|
||||
setPagination({ page: page });
|
||||
reload();
|
||||
}
|
||||
return propsData
|
||||
})
|
||||
|
||||
//获取分页信息
|
||||
const pagination = computed(() => toRaw(unref(getPaginationInfo)))
|
||||
//分页数量切换
|
||||
function updatePageSize(size) {
|
||||
setPagination({ page: 1, pageSize: size });
|
||||
reload();
|
||||
}
|
||||
|
||||
function setProps(props: Partial<BasicTableProps>) {
|
||||
innerPropsRef.value = { ...unref(innerPropsRef), ...props };
|
||||
}
|
||||
//密度切换
|
||||
function densitySelect(e) {
|
||||
state.tableSize = e;
|
||||
}
|
||||
|
||||
const tableAction: TableActionType = {
|
||||
reload,
|
||||
setColumns,
|
||||
setLoading,
|
||||
setProps,
|
||||
getColumns,
|
||||
getPageColumns,
|
||||
getCacheColumns,
|
||||
setCacheColumnsField,
|
||||
emit,
|
||||
getSize: () => {
|
||||
return unref(getBindValues).size as SizeType;
|
||||
},
|
||||
};
|
||||
//选中行
|
||||
function updateCheckedRowKeys(rowKeys) {
|
||||
emit('update:checked-row-keys', rowKeys);
|
||||
}
|
||||
|
||||
createTableContext({ ...tableAction, wrapRef, getBindValues });
|
||||
//重置 Columns
|
||||
const resetColumns = () => {
|
||||
columns.map((item) => {
|
||||
item.isShow = true;
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
...toRefs(state),
|
||||
getBindValues,
|
||||
densityOptions,
|
||||
reload,
|
||||
densitySelect,
|
||||
updatePage,
|
||||
updatePageSize,
|
||||
updateCheckedRowKeys,
|
||||
pagination,
|
||||
resetColumns,
|
||||
tableAction
|
||||
}
|
||||
}
|
||||
})
|
||||
//获取表格大小
|
||||
const getTableSize = computed(() => state.tableSize);
|
||||
|
||||
//组装表格信息
|
||||
const getBindValues = computed(() => {
|
||||
const tableData = unref(getDataSourceRef);
|
||||
let propsData = {
|
||||
...unref(getProps),
|
||||
loading: unref(getLoading),
|
||||
columns: toRaw(unref(getPageColumns)),
|
||||
rowKey: unref(getRowKey),
|
||||
data: tableData,
|
||||
size: unref(getTableSize),
|
||||
remote: true,
|
||||
};
|
||||
return propsData;
|
||||
});
|
||||
|
||||
//获取分页信息
|
||||
const pagination = computed(() => toRaw(unref(getPaginationInfo)));
|
||||
|
||||
function setProps(props: Partial<BasicTableProps>) {
|
||||
innerPropsRef.value = { ...unref(innerPropsRef), ...props };
|
||||
}
|
||||
|
||||
const tableAction: TableActionType = {
|
||||
reload,
|
||||
setColumns,
|
||||
setLoading,
|
||||
setProps,
|
||||
getColumns,
|
||||
getPageColumns,
|
||||
getCacheColumns,
|
||||
setCacheColumnsField,
|
||||
emit,
|
||||
getSize: () => {
|
||||
return unref(getBindValues).size as SizeType;
|
||||
},
|
||||
};
|
||||
|
||||
createTableContext({ ...tableAction, wrapRef, getBindValues });
|
||||
|
||||
return {
|
||||
...toRefs(state),
|
||||
getBindValues,
|
||||
densityOptions,
|
||||
reload,
|
||||
densitySelect,
|
||||
updatePage,
|
||||
updatePageSize,
|
||||
updateCheckedRowKeys,
|
||||
pagination,
|
||||
resetColumns,
|
||||
tableAction,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang='less' scoped>
|
||||
.table-toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 0 0 16px 0;
|
||||
|
||||
&-left {
|
||||
<style lang="less" scoped>
|
||||
.table-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
flex: 1;
|
||||
justify-content: space-between;
|
||||
padding: 0 0 16px 0;
|
||||
|
||||
&-title {
|
||||
&-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
flex: 1;
|
||||
|
||||
&-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-right {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
flex: 1;
|
||||
&-right {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
flex: 1;
|
||||
|
||||
&-icon {
|
||||
margin-left: 12px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
color: var(--text-color);
|
||||
&-icon {
|
||||
margin-left: 12px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
color: var(--text-color);
|
||||
|
||||
:hover {
|
||||
color: #1890ff;
|
||||
:hover {
|
||||
color: #1890ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-toolbar-inner-popover-title {
|
||||
padding: 2px 0;
|
||||
}
|
||||
.table-toolbar-inner-popover-title {
|
||||
padding: 2px 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -5,18 +5,17 @@
|
||||
<n-button v-bind="action" class="mx-2">{{ action.label }}</n-button>
|
||||
</template>
|
||||
<n-dropdown
|
||||
v-if="dropDownActions && getDropdownList.length"
|
||||
trigger="hover"
|
||||
:options="getDropdownList"
|
||||
@select="select"
|
||||
v-if="dropDownActions && getDropdownList.length"
|
||||
trigger="hover"
|
||||
:options="getDropdownList"
|
||||
@select="select"
|
||||
>
|
||||
<slot name="more"></slot>
|
||||
<n-button v-bind="getMoreProps" class="mx-2" v-if="!$slots.more" icon-placement="right">
|
||||
|
||||
<div class="flex items-center">
|
||||
<span>更多</span>
|
||||
<n-icon size="14" class="ml-1">
|
||||
<DownOutlined/>
|
||||
<DownOutlined />
|
||||
</n-icon>
|
||||
</div>
|
||||
<!-- <template #icon>-->
|
||||
@@ -29,64 +28,56 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, computed, toRaw } from 'vue';
|
||||
import { ActionItem } from '@/components/Table';
|
||||
import { usePermission } from '@/hooks/web/usePermission';
|
||||
import { isString, isBoolean, isFunction } from "@/utils/is";
|
||||
import { DownOutlined } from '@vicons/antd'
|
||||
import { defineComponent, PropType, computed, toRaw } from 'vue';
|
||||
import { ActionItem } from '@/components/Table';
|
||||
import { usePermission } from '@/hooks/web/usePermission';
|
||||
import { isBoolean, isFunction } from '@/utils/is';
|
||||
import { DownOutlined } from '@vicons/antd';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TableAction',
|
||||
components: { DownOutlined },
|
||||
props: {
|
||||
actions: {
|
||||
type: Array as PropType<ActionItem[]>,
|
||||
default: null,
|
||||
export default defineComponent({
|
||||
name: 'TableAction',
|
||||
components: { DownOutlined },
|
||||
props: {
|
||||
actions: {
|
||||
type: Array as PropType<ActionItem[]>,
|
||||
default: null,
|
||||
},
|
||||
dropDownActions: {
|
||||
type: Array as PropType<ActionItem[]>,
|
||||
default: null,
|
||||
},
|
||||
style: {
|
||||
type: String as PropType<String>,
|
||||
default: 'button',
|
||||
},
|
||||
select: {
|
||||
type: Function as PropType<Function>,
|
||||
default: () => {},
|
||||
},
|
||||
},
|
||||
dropDownActions: {
|
||||
type: Array as PropType<ActionItem[]>,
|
||||
default: null,
|
||||
},
|
||||
style: {
|
||||
type: String as PropType<String>,
|
||||
default: 'button'
|
||||
},
|
||||
select:{
|
||||
type: Function as PropType<Function>,
|
||||
default: () =>{ }
|
||||
}
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const { hasPermission } = usePermission();
|
||||
setup(props) {
|
||||
const { hasPermission } = usePermission();
|
||||
|
||||
const getTooltip = computed(() => {
|
||||
return (data: string | TooltipProps): TooltipProps => {
|
||||
if (isString(data)) {
|
||||
return { title: data, placement: 'bottom' };
|
||||
} else {
|
||||
return Object.assign({ placement: 'bottom' }, data);
|
||||
}
|
||||
};
|
||||
});
|
||||
const actionType =
|
||||
props.style === 'button' ? 'default' : props.style === 'text' ? 'primary' : 'default';
|
||||
const actionText =
|
||||
props.style === 'button' ? undefined : props.style === 'text' ? true : undefined;
|
||||
|
||||
const actionType = props.style === 'button' ? 'default' : props.style === 'text' ? 'primary' : 'default'
|
||||
const actionText = props.style === 'button' ? undefined : props.style === 'text' ? true : undefined
|
||||
|
||||
const getMoreProps = computed(() => {
|
||||
const getMoreProps = computed(() => {
|
||||
return {
|
||||
text: actionText,
|
||||
type: actionType,
|
||||
size: "small"
|
||||
}
|
||||
})
|
||||
size: 'small',
|
||||
};
|
||||
});
|
||||
|
||||
const getDropdownList = computed(() => {
|
||||
return (toRaw(props.dropDownActions) || [])
|
||||
const getDropdownList = computed(() => {
|
||||
return (toRaw(props.dropDownActions) || [])
|
||||
.filter((action) => {
|
||||
return hasPermission(action.auth) && isIfShow(action);
|
||||
})
|
||||
.map((action, index) => {
|
||||
const { label, popConfirm } = action;
|
||||
.map((action) => {
|
||||
const { popConfirm } = action;
|
||||
return {
|
||||
size: 'small',
|
||||
text: actionText,
|
||||
@@ -94,27 +85,27 @@ export default defineComponent({
|
||||
...action,
|
||||
...popConfirm,
|
||||
onConfirm: popConfirm?.confirm,
|
||||
onCancel: popConfirm?.cancel
|
||||
onCancel: popConfirm?.cancel,
|
||||
};
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function isIfShow(action: ActionItem): boolean {
|
||||
const ifShow = action.ifShow;
|
||||
function isIfShow(action: ActionItem): boolean {
|
||||
const ifShow = action.ifShow;
|
||||
|
||||
let isIfShow = true;
|
||||
let isIfShow = true;
|
||||
|
||||
if (isBoolean(ifShow)) {
|
||||
isIfShow = ifShow;
|
||||
if (isBoolean(ifShow)) {
|
||||
isIfShow = ifShow;
|
||||
}
|
||||
if (isFunction(ifShow)) {
|
||||
isIfShow = ifShow(action);
|
||||
}
|
||||
return isIfShow;
|
||||
}
|
||||
if (isFunction(ifShow)) {
|
||||
isIfShow = ifShow(action);
|
||||
}
|
||||
return isIfShow;
|
||||
}
|
||||
|
||||
const getActions = computed(() => {
|
||||
return (toRaw(props.actions) || [])
|
||||
const getActions = computed(() => {
|
||||
return (toRaw(props.actions) || [])
|
||||
.filter((action) => {
|
||||
return hasPermission(action.auth) && isIfShow(action);
|
||||
})
|
||||
@@ -132,14 +123,13 @@ export default defineComponent({
|
||||
enable: !!popConfirm,
|
||||
};
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
getActions,
|
||||
getDropdownList,
|
||||
getTooltip,
|
||||
getMoreProps
|
||||
}
|
||||
}
|
||||
})
|
||||
return {
|
||||
getActions,
|
||||
getDropdownList,
|
||||
getMoreProps,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -5,46 +5,62 @@
|
||||
<n-popover trigger="click" :width="230" class="toolbar-popover" placement="bottom-end">
|
||||
<template #trigger>
|
||||
<n-icon size="18">
|
||||
<SettingOutlined/>
|
||||
<SettingOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
<template #header>
|
||||
<div class="table-toolbar-inner-popover-title">
|
||||
<n-space>
|
||||
<n-checkbox v-model:checked="checkAll" @update:checked="onCheckAll">列展示</n-checkbox>
|
||||
<n-checkbox v-model:checked="selection" @update:checked="onSelection">勾选列</n-checkbox>
|
||||
<n-button text type="info" size="small" class="mt-1" @click="resetColumns">重置</n-button>
|
||||
<n-checkbox v-model:checked="checkAll" @update:checked="onCheckAll"
|
||||
>列展示</n-checkbox
|
||||
>
|
||||
<n-checkbox v-model:checked="selection" @update:checked="onSelection"
|
||||
>勾选列</n-checkbox
|
||||
>
|
||||
<n-button text type="info" size="small" class="mt-1" @click="resetColumns"
|
||||
>重置</n-button
|
||||
>
|
||||
</n-space>
|
||||
</div>
|
||||
</template>
|
||||
<div class="table-toolbar-inner">
|
||||
<n-checkbox-group v-model:value="checkList" @update:value="onChange">
|
||||
<Draggable v-model="columnsList" animation="300" item-key="key" @end="draggableEnd">
|
||||
<template #item="{element, index}">
|
||||
<div class="table-toolbar-inner-checkbox"
|
||||
:class="{'table-toolbar-inner-checkbox-dark':getDarkTheme === true}">
|
||||
<template #item="{ element }">
|
||||
<div
|
||||
class="table-toolbar-inner-checkbox"
|
||||
:class="{ 'table-toolbar-inner-checkbox-dark': getDarkTheme === true }"
|
||||
>
|
||||
<span class="drag-icon">
|
||||
<n-icon size="18">
|
||||
<DragOutlined/>
|
||||
<DragOutlined />
|
||||
</n-icon>
|
||||
</span>
|
||||
<n-checkbox :value="element.key" :label="element.title"/>
|
||||
<n-checkbox :value="element.key" :label="element.title" />
|
||||
<div class="fixed-item">
|
||||
<n-tooltip trigger="hover" placement="bottom">
|
||||
<template #trigger>
|
||||
<n-icon size="18" :color="element.fixed === 'left' ? '#2080f0':undefined"
|
||||
class="cursor-pointer" @click="fixedColumn(element,'left')">
|
||||
<VerticalRightOutlined/>
|
||||
<n-icon
|
||||
size="18"
|
||||
:color="element.fixed === 'left' ? '#2080f0' : undefined"
|
||||
class="cursor-pointer"
|
||||
@click="fixedColumn(element, 'left')"
|
||||
>
|
||||
<VerticalRightOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
<span>固定到左侧</span>
|
||||
</n-tooltip>
|
||||
<n-divider vertical/>
|
||||
<n-divider vertical />
|
||||
<n-tooltip trigger="hover" placement="bottom">
|
||||
<template #trigger>
|
||||
<n-icon size="18" :color="element.fixed === 'right' ? '#2080f0':undefined"
|
||||
class="cursor-pointer" @click="fixedColumn(element,'right')">
|
||||
<VerticalLeftOutlined/>
|
||||
<n-icon
|
||||
size="18"
|
||||
:color="element.fixed === 'right' ? '#2080f0' : undefined"
|
||||
class="cursor-pointer"
|
||||
@click="fixedColumn(element, 'right')"
|
||||
>
|
||||
<VerticalLeftOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
<span>固定到右侧</span>
|
||||
@@ -63,221 +79,226 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { ref, defineComponent, reactive, unref, toRaw, computed, toRefs, watchEffect } from "vue"
|
||||
import { useTableContext } from '../../hooks/useTableContext';
|
||||
import { ReloadOutlined, ColumnHeightOutlined, SettingOutlined, DragOutlined, VerticalRightOutlined, VerticalLeftOutlined } from '@vicons/antd'
|
||||
import Draggable from 'vuedraggable/src/vuedraggable'
|
||||
import { useDesignSetting } from "@/hooks/setting/useDesignSetting";
|
||||
import { ref, defineComponent, reactive, unref, toRaw, computed, toRefs, watchEffect } from 'vue';
|
||||
import { useTableContext } from '../../hooks/useTableContext';
|
||||
import {
|
||||
SettingOutlined,
|
||||
DragOutlined,
|
||||
VerticalRightOutlined,
|
||||
VerticalLeftOutlined,
|
||||
} from '@vicons/antd';
|
||||
import Draggable from 'vuedraggable/src/vuedraggable';
|
||||
import { useDesignSetting } from '@/hooks/setting/useDesignSetting';
|
||||
|
||||
interface Options {
|
||||
title: string;
|
||||
key: string;
|
||||
fixed?: boolean | 'left' | 'right';
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ColumnSetting',
|
||||
components: {
|
||||
ReloadOutlined, ColumnHeightOutlined, SettingOutlined, DragOutlined, Draggable,
|
||||
VerticalRightOutlined, VerticalLeftOutlined
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const { getDarkTheme } = useDesignSetting()
|
||||
const table = useTableContext();
|
||||
const columnsList = ref<Options[]>([]);
|
||||
const cacheColumnsList = ref<Options[]>([]);
|
||||
|
||||
const state = reactive({
|
||||
selection: false,
|
||||
checkAll: true,
|
||||
checkList: [],
|
||||
defaultCheckList: []
|
||||
})
|
||||
|
||||
const getSelection = computed(() => {
|
||||
return state.selection
|
||||
})
|
||||
|
||||
watchEffect(() => {
|
||||
const columns = table.getColumns();
|
||||
if (columns.length) {
|
||||
init();
|
||||
}
|
||||
});
|
||||
|
||||
//初始化
|
||||
function init() {
|
||||
const columns = getColumns();
|
||||
const checkList = columns.map(item => item.key)
|
||||
state.checkList = checkList
|
||||
state.defaultCheckList = checkList
|
||||
columnsList.value = columns
|
||||
cacheColumnsList.value = columns
|
||||
}
|
||||
|
||||
//切换
|
||||
function onChange(checkList) {
|
||||
if (state.selection) {
|
||||
checkList.unshift('selection')
|
||||
}
|
||||
setColumns(checkList)
|
||||
}
|
||||
|
||||
//设置
|
||||
function setColumns(columns) {
|
||||
table.setColumns(columns)
|
||||
}
|
||||
|
||||
//获取
|
||||
function getColumns() {
|
||||
let newRet = []
|
||||
table.getColumns().forEach(item => {
|
||||
newRet.push({ ...item })
|
||||
})
|
||||
return newRet
|
||||
}
|
||||
|
||||
//重置
|
||||
function resetColumns() {
|
||||
state.checkList = [...state.defaultCheckList]
|
||||
state.checkAll = true;
|
||||
let cacheColumnsKeys: any[] = table.getCacheColumns()
|
||||
let newColumns = cacheColumnsKeys.map(item => {
|
||||
return {
|
||||
...item,
|
||||
fixed: undefined
|
||||
}
|
||||
})
|
||||
setColumns(newColumns);
|
||||
columnsList.value = newColumns
|
||||
}
|
||||
|
||||
//全选
|
||||
function onCheckAll(e) {
|
||||
let checkList = table.getCacheColumns(true)
|
||||
if (e) {
|
||||
setColumns(checkList);
|
||||
state.checkList = checkList
|
||||
} else {
|
||||
setColumns([]);
|
||||
state.checkList = []
|
||||
}
|
||||
}
|
||||
|
||||
//拖拽排序
|
||||
function draggableEnd() {
|
||||
const newColumns = toRaw(unref(columnsList))
|
||||
columnsList.value = newColumns
|
||||
setColumns(newColumns);
|
||||
}
|
||||
|
||||
//勾选列
|
||||
function onSelection(e) {
|
||||
let checkList = table.getCacheColumns()
|
||||
if (e) {
|
||||
checkList.unshift({ type: 'selection', key: 'selection' })
|
||||
setColumns(checkList);
|
||||
} else {
|
||||
checkList.splice(0, 1)
|
||||
setColumns(checkList);
|
||||
}
|
||||
}
|
||||
|
||||
//固定
|
||||
function fixedColumn(item, fixed) {
|
||||
console.log('item:', item)
|
||||
if (!state.checkList.includes(item.key)) return;
|
||||
let columns = getColumns();
|
||||
const isFixed = item.fixed === fixed ? undefined : fixed
|
||||
let index = columns.findIndex(res => res.key === item.key)
|
||||
console.log('index:', index)
|
||||
if (index !== -1) {
|
||||
columns[index].fixed = isFixed;
|
||||
}
|
||||
table.setCacheColumnsField(item.key, { fixed: isFixed })
|
||||
columnsList.value[index].fixed = isFixed
|
||||
console.log('columnsList:', columnsList.value)
|
||||
setColumns(columns);
|
||||
}
|
||||
|
||||
return {
|
||||
...toRefs(state),
|
||||
columnsList,
|
||||
getDarkTheme,
|
||||
onChange,
|
||||
onCheckAll,
|
||||
onSelection,
|
||||
resetColumns,
|
||||
fixedColumn,
|
||||
draggableEnd,
|
||||
getSelection
|
||||
}
|
||||
interface Options {
|
||||
title: string;
|
||||
key: string;
|
||||
fixed?: boolean | 'left' | 'right';
|
||||
}
|
||||
})
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ColumnSetting',
|
||||
components: {
|
||||
SettingOutlined,
|
||||
DragOutlined,
|
||||
Draggable,
|
||||
VerticalRightOutlined,
|
||||
VerticalLeftOutlined,
|
||||
},
|
||||
setup() {
|
||||
const { getDarkTheme } = useDesignSetting();
|
||||
const table = useTableContext();
|
||||
const columnsList = ref<Options[]>([]);
|
||||
const cacheColumnsList = ref<Options[]>([]);
|
||||
|
||||
const state = reactive({
|
||||
selection: false,
|
||||
checkAll: true,
|
||||
checkList: [],
|
||||
defaultCheckList: [],
|
||||
});
|
||||
|
||||
const getSelection = computed(() => {
|
||||
return state.selection;
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
const columns = table.getColumns();
|
||||
if (columns.length) {
|
||||
init();
|
||||
}
|
||||
});
|
||||
|
||||
//初始化
|
||||
function init() {
|
||||
const columns: any[] = getColumns();
|
||||
const checkList: any = columns.map((item) => item.key);
|
||||
state.checkList = checkList;
|
||||
state.defaultCheckList = checkList;
|
||||
columnsList.value = columns;
|
||||
cacheColumnsList.value = columns;
|
||||
}
|
||||
|
||||
//切换
|
||||
function onChange(checkList) {
|
||||
if (state.selection) {
|
||||
checkList.unshift('selection');
|
||||
}
|
||||
setColumns(checkList);
|
||||
}
|
||||
|
||||
//设置
|
||||
function setColumns(columns) {
|
||||
table.setColumns(columns);
|
||||
}
|
||||
|
||||
//获取
|
||||
function getColumns() {
|
||||
let newRet = [];
|
||||
table.getColumns().forEach((item) => {
|
||||
newRet.push({ ...item });
|
||||
});
|
||||
return newRet;
|
||||
}
|
||||
|
||||
//重置
|
||||
function resetColumns() {
|
||||
state.checkList = [...state.defaultCheckList];
|
||||
state.checkAll = true;
|
||||
let cacheColumnsKeys: any[] = table.getCacheColumns();
|
||||
let newColumns = cacheColumnsKeys.map((item) => {
|
||||
return {
|
||||
...item,
|
||||
fixed: undefined,
|
||||
};
|
||||
});
|
||||
setColumns(newColumns);
|
||||
columnsList.value = newColumns;
|
||||
}
|
||||
|
||||
//全选
|
||||
function onCheckAll(e) {
|
||||
let checkList = table.getCacheColumns(true);
|
||||
if (e) {
|
||||
setColumns(checkList);
|
||||
state.checkList = checkList;
|
||||
} else {
|
||||
setColumns([]);
|
||||
state.checkList = [];
|
||||
}
|
||||
}
|
||||
|
||||
//拖拽排序
|
||||
function draggableEnd() {
|
||||
const newColumns = toRaw(unref(columnsList));
|
||||
columnsList.value = newColumns;
|
||||
setColumns(newColumns);
|
||||
}
|
||||
|
||||
//勾选列
|
||||
function onSelection(e) {
|
||||
let checkList = table.getCacheColumns();
|
||||
if (e) {
|
||||
checkList.unshift({ type: 'selection', key: 'selection' });
|
||||
setColumns(checkList);
|
||||
} else {
|
||||
checkList.splice(0, 1);
|
||||
setColumns(checkList);
|
||||
}
|
||||
}
|
||||
|
||||
//固定
|
||||
function fixedColumn(item, fixed) {
|
||||
if (!state.checkList.includes(item.key)) return;
|
||||
let columns = getColumns();
|
||||
const isFixed = item.fixed === fixed ? undefined : fixed;
|
||||
let index = columns.findIndex((res) => res.key === item.key);
|
||||
if (index !== -1) {
|
||||
columns[index].fixed = isFixed;
|
||||
}
|
||||
table.setCacheColumnsField(item.key, { fixed: isFixed });
|
||||
columnsList.value[index].fixed = isFixed;
|
||||
setColumns(columns);
|
||||
}
|
||||
|
||||
return {
|
||||
...toRefs(state),
|
||||
columnsList,
|
||||
getDarkTheme,
|
||||
onChange,
|
||||
onCheckAll,
|
||||
onSelection,
|
||||
resetColumns,
|
||||
fixedColumn,
|
||||
draggableEnd,
|
||||
getSelection,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.table-toolbar {
|
||||
&-inner-popover-title {
|
||||
padding: 3px 0;
|
||||
}
|
||||
.table-toolbar {
|
||||
&-inner-popover-title {
|
||||
padding: 3px 0;
|
||||
}
|
||||
|
||||
&-right {
|
||||
&-icon {
|
||||
margin-left: 12px;
|
||||
font-size: 16px;
|
||||
color: var(--text-color);
|
||||
cursor: pointer;
|
||||
&-right {
|
||||
&-icon {
|
||||
margin-left: 12px;
|
||||
font-size: 16px;
|
||||
color: var(--text-color);
|
||||
cursor: pointer;
|
||||
|
||||
:hover {
|
||||
color: #1890ff;
|
||||
:hover {
|
||||
color: #1890ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-toolbar-inner {
|
||||
&-checkbox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px 14px;
|
||||
|
||||
&:hover {
|
||||
background: #e6f7ff;
|
||||
}
|
||||
|
||||
.drag-icon {
|
||||
display: inline-flex;
|
||||
margin-right: 8px;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.fixed-item {
|
||||
.table-toolbar-inner {
|
||||
&-checkbox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.ant-checkbox-wrapper {
|
||||
flex: 1;
|
||||
padding: 10px 14px;
|
||||
|
||||
&:hover {
|
||||
color: #1890ff !important;
|
||||
background: #e6f7ff;
|
||||
}
|
||||
|
||||
.drag-icon {
|
||||
display: inline-flex;
|
||||
margin-right: 8px;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.fixed-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.ant-checkbox-wrapper {
|
||||
flex: 1;
|
||||
|
||||
&:hover {
|
||||
color: #1890ff !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-checkbox-dark {
|
||||
&:hover {
|
||||
background: hsla(0, 0%, 100%, 0.08);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-checkbox-dark {
|
||||
&:hover {
|
||||
background: hsla(0, 0%, 100%, .08);
|
||||
.toolbar-popover {
|
||||
.n-popover__content {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.toolbar-popover {
|
||||
.n-popover__content {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import componentSetting from '@/settings/componentSetting'
|
||||
import componentSetting from '@/settings/componentSetting';
|
||||
|
||||
const { table } = componentSetting
|
||||
const { table } = componentSetting;
|
||||
|
||||
const { apiSetting, defaultPageSize, pageSizes } = table;
|
||||
|
||||
@@ -9,7 +9,3 @@ export const DEFAULTPAGESIZE = defaultPageSize;
|
||||
export const APISETTING = apiSetting;
|
||||
|
||||
export const PAGESIZES = pageSizes;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,126 +1,125 @@
|
||||
import { ref, Ref, ComputedRef, unref, computed, watch, toRaw } from 'vue';
|
||||
import type { BasicColumn, BasicTableProps } from '../types/table';
|
||||
import { isEqual, cloneDeep } from 'lodash-es';
|
||||
import { isArray, isString } from '@/utils/is';
|
||||
import { isArray, isString, isBoolean, isFunction } from '@/utils/is';
|
||||
import { usePermission } from '@/hooks/web/usePermission';
|
||||
import { isString, isBoolean, isFunction } from "@/utils/is";
|
||||
import { ActionItem } from "@/components/Table";
|
||||
import { ActionItem } from '@/components/Table';
|
||||
|
||||
export function useColumns(propsRef: ComputedRef<BasicTableProps>) {
|
||||
const columnsRef = ref(unref(propsRef).columns) as unknown as Ref<BasicColumn[]>;
|
||||
let cacheColumns = unref(propsRef).columns;
|
||||
const columnsRef = ref(unref(propsRef).columns) as unknown as Ref<BasicColumn[]>;
|
||||
let cacheColumns = unref(propsRef).columns;
|
||||
|
||||
const getColumnsRef = computed(() => {
|
||||
const columns = cloneDeep(unref(columnsRef));
|
||||
const getColumnsRef = computed(() => {
|
||||
const columns = cloneDeep(unref(columnsRef));
|
||||
|
||||
handleActionColumn(propsRef, columns);
|
||||
if (!columns) return [];
|
||||
return columns;
|
||||
})
|
||||
handleActionColumn(propsRef, columns);
|
||||
if (!columns) return [];
|
||||
return columns;
|
||||
});
|
||||
|
||||
const { hasPermission } = usePermission();
|
||||
const { hasPermission } = usePermission();
|
||||
|
||||
function isIfShow(action: ActionItem): boolean {
|
||||
const ifShow = action.ifShow;
|
||||
function isIfShow(action: ActionItem): boolean {
|
||||
const ifShow = action.ifShow;
|
||||
|
||||
let isIfShow = true;
|
||||
let isIfShow = true;
|
||||
|
||||
if (isBoolean(ifShow)) {
|
||||
isIfShow = ifShow;
|
||||
}
|
||||
if (isFunction(ifShow)) {
|
||||
isIfShow = ifShow(action);
|
||||
}
|
||||
return isIfShow;
|
||||
if (isBoolean(ifShow)) {
|
||||
isIfShow = ifShow;
|
||||
}
|
||||
if (isFunction(ifShow)) {
|
||||
isIfShow = ifShow(action);
|
||||
}
|
||||
return isIfShow;
|
||||
}
|
||||
|
||||
const getPageColumns = computed(() => {
|
||||
const pageColumns = unref(getColumnsRef);
|
||||
const columns = cloneDeep(pageColumns);
|
||||
return columns.filter((column) => {
|
||||
return hasPermission(column.auth) && isIfShow(column);
|
||||
})
|
||||
})
|
||||
const getPageColumns = computed(() => {
|
||||
const pageColumns = unref(getColumnsRef);
|
||||
const columns = cloneDeep(pageColumns);
|
||||
return columns.filter((column) => {
|
||||
// @ts-ignore
|
||||
return hasPermission(column.auth) && isIfShow(column);
|
||||
});
|
||||
});
|
||||
|
||||
watch(
|
||||
() => unref(propsRef).columns,
|
||||
(columns) => {
|
||||
columnsRef.value = columns;
|
||||
cacheColumns = columns;
|
||||
watch(
|
||||
() => unref(propsRef).columns,
|
||||
(columns) => {
|
||||
columnsRef.value = columns;
|
||||
cacheColumns = columns;
|
||||
}
|
||||
);
|
||||
|
||||
function handleActionColumn(propsRef: ComputedRef<BasicTableProps>, columns: BasicColumn[]) {
|
||||
const { actionColumn } = unref(propsRef);
|
||||
if (!actionColumn) return;
|
||||
// @ts-ignore
|
||||
columns.push({
|
||||
...actionColumn,
|
||||
});
|
||||
}
|
||||
|
||||
//设置
|
||||
function setColumns(columnList: string[]) {
|
||||
const columns: any[] = cloneDeep(columnList);
|
||||
if (!isArray(columns)) return;
|
||||
|
||||
if (!columns.length) {
|
||||
columnsRef.value = [];
|
||||
return;
|
||||
}
|
||||
const cacheKeys = cacheColumns.map((item) => item.key);
|
||||
//针对拖拽排序
|
||||
if (!isString(columns[0])) {
|
||||
columnsRef.value = columns;
|
||||
} else {
|
||||
const newColumns: any[] = [];
|
||||
cacheColumns.forEach((item) => {
|
||||
if (columnList.includes(item.key)) {
|
||||
newColumns.push({ ...item });
|
||||
}
|
||||
);
|
||||
|
||||
function handleActionColumn(propsRef: ComputedRef<BasicTableProps>, columns: BasicColumn[]) {
|
||||
const { actionColumn } = unref(propsRef);
|
||||
if (!actionColumn) return;
|
||||
columns.push({
|
||||
...actionColumn
|
||||
});
|
||||
if (!isEqual(cacheKeys, columns)) {
|
||||
newColumns.sort((prev, next) => {
|
||||
return cacheKeys.indexOf(prev.key) - cacheKeys.indexOf(next.key);
|
||||
});
|
||||
}
|
||||
columnsRef.value = newColumns;
|
||||
}
|
||||
}
|
||||
|
||||
//设置
|
||||
function setColumns(columnList: string[]) {
|
||||
const columns: any[] = cloneDeep(columnList);
|
||||
if (!isArray(columns)) return;
|
||||
//获取
|
||||
function getColumns() {
|
||||
const columns = toRaw(unref(getColumnsRef));
|
||||
return columns.map((item) => {
|
||||
return { ...item, title: item.title, key: item.key, fixed: item.fixed || undefined };
|
||||
});
|
||||
}
|
||||
|
||||
if (!columns.length) {
|
||||
columnsRef.value = [];
|
||||
return;
|
||||
}
|
||||
const cacheKeys = cacheColumns.map((item) => item.key);
|
||||
//针对拖拽排序
|
||||
if (!isString(columns[0])) {
|
||||
columnsRef.value = columns;
|
||||
} else {
|
||||
const newColumns: any[] = []
|
||||
cacheColumns.forEach(item => {
|
||||
if (columnList.includes(item.key)) {
|
||||
newColumns.push({ ...item })
|
||||
}
|
||||
})
|
||||
if (!isEqual(cacheKeys, columns)) {
|
||||
newColumns.sort((prev, next) => {
|
||||
return (
|
||||
cacheKeys.indexOf(prev.key) - cacheKeys.indexOf(next.key)
|
||||
);
|
||||
});
|
||||
}
|
||||
columnsRef.value = newColumns
|
||||
}
|
||||
//获取原始
|
||||
function getCacheColumns(isKey?: boolean): any[] {
|
||||
return isKey ? cacheColumns.map((item) => item.key) : cacheColumns;
|
||||
}
|
||||
|
||||
//更新原始数据单个字段
|
||||
function setCacheColumnsField(dataIndex: string | undefined, value: Partial<BasicColumn>) {
|
||||
if (!dataIndex || !value) {
|
||||
return;
|
||||
}
|
||||
cacheColumns.forEach((item) => {
|
||||
if (item.key === dataIndex) {
|
||||
Object.assign(item, value);
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//获取
|
||||
function getColumns() {
|
||||
let columns = toRaw(unref(getColumnsRef));
|
||||
return columns.map(item => {
|
||||
return { ...item, title: item.title, key: item.key, fixed: item.fixed || undefined }
|
||||
})
|
||||
}
|
||||
|
||||
//获取原始
|
||||
function getCacheColumns(isKey?: boolean): any[] {
|
||||
return isKey ? cacheColumns.map(item => item.key) : cacheColumns;
|
||||
}
|
||||
|
||||
//更新原始数据单个字段
|
||||
function setCacheColumnsField(dataIndex: string | undefined, value: Partial<BasicColumn>) {
|
||||
if (!dataIndex || !value) {
|
||||
return;
|
||||
}
|
||||
cacheColumns.forEach((item) => {
|
||||
if (item.key === dataIndex) {
|
||||
Object.assign(item, value);
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
getColumnsRef,
|
||||
getCacheColumns,
|
||||
setCacheColumnsField,
|
||||
setColumns,
|
||||
getColumns,
|
||||
getPageColumns
|
||||
};
|
||||
return {
|
||||
getColumnsRef,
|
||||
getCacheColumns,
|
||||
setCacheColumnsField,
|
||||
setColumns,
|
||||
getColumns,
|
||||
getPageColumns,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,137 +5,134 @@ import { isBoolean } from '@/utils/is';
|
||||
import { APISETTING } from '../const';
|
||||
|
||||
export function useDataSource(
|
||||
propsRef: ComputedRef<BasicTableProps>,
|
||||
{
|
||||
getPaginationInfo,
|
||||
setPagination,
|
||||
setLoading,
|
||||
tableData
|
||||
},
|
||||
emit
|
||||
propsRef: ComputedRef<BasicTableProps>,
|
||||
{ getPaginationInfo, setPagination, setLoading, tableData },
|
||||
emit
|
||||
) {
|
||||
const dataSourceRef = ref([]);
|
||||
const dataSourceRef = ref([]);
|
||||
|
||||
watchEffect(() => {
|
||||
tableData.value = unref(dataSourceRef);
|
||||
});
|
||||
watchEffect(() => {
|
||||
tableData.value = unref(dataSourceRef);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => unref(propsRef).dataSource,
|
||||
() => {
|
||||
const { dataSource }: any = unref(propsRef);
|
||||
dataSource && (dataSourceRef.value = dataSource);
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
watch(
|
||||
() => unref(propsRef).dataSource,
|
||||
() => {
|
||||
const { dataSource }: any = unref(propsRef);
|
||||
dataSource && (dataSourceRef.value = dataSource);
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
const getRowKey = computed(() => {
|
||||
const { rowKey }: any = unref(propsRef);
|
||||
return rowKey ? rowKey : () => {
|
||||
return 'key'
|
||||
const getRowKey = computed(() => {
|
||||
const { rowKey }: any = unref(propsRef);
|
||||
return rowKey
|
||||
? rowKey
|
||||
: () => {
|
||||
return 'key';
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
const getDataSourceRef = computed(() => {
|
||||
const dataSource = unref(dataSourceRef);
|
||||
if (!dataSource || dataSource.length === 0) {
|
||||
return unref(dataSourceRef);
|
||||
}
|
||||
return unref(dataSourceRef);
|
||||
});
|
||||
|
||||
async function fetch(opt?) {
|
||||
try {
|
||||
setLoading(true);
|
||||
const { request, pagination }: any = unref(propsRef);
|
||||
|
||||
//组装分页信息
|
||||
const pageField = APISETTING.pageField
|
||||
const sizeField = APISETTING.sizeField
|
||||
const totalField = APISETTING.totalField
|
||||
const listField = APISETTING.listField
|
||||
|
||||
let pageParams = {};
|
||||
const { page = 1, pageSize = 10 } = unref(getPaginationInfo) as PaginationProps;
|
||||
|
||||
if ((isBoolean(pagination) && !pagination) || isBoolean(getPaginationInfo)) {
|
||||
pageParams = {};
|
||||
} else {
|
||||
pageParams[pageField] = (opt && opt[pageField]) || page;
|
||||
pageParams[sizeField] = pageSize;
|
||||
}
|
||||
|
||||
let params = {
|
||||
...pageParams,
|
||||
}
|
||||
const res = await request(params);
|
||||
|
||||
const resultTotal = res[totalField] || 0
|
||||
const currentPage = res[pageField]
|
||||
|
||||
// 如果数据异常,需获取正确的页码再次执行
|
||||
if (resultTotal) {
|
||||
const currentTotalPage = Math.ceil(resultTotal / pageSize);
|
||||
if (page > currentTotalPage) {
|
||||
setPagination({
|
||||
[pageField]: currentTotalPage,
|
||||
});
|
||||
fetch(opt);
|
||||
}
|
||||
}
|
||||
let resultInfo = res[listField] ? res[listField] : []
|
||||
dataSourceRef.value = resultInfo;
|
||||
setPagination({
|
||||
[pageField]: currentPage,
|
||||
[totalField]: resultTotal,
|
||||
});
|
||||
if (opt && opt[pageField]) {
|
||||
setPagination({
|
||||
[pageField]: opt[pageField] || 1,
|
||||
});
|
||||
}
|
||||
emit('fetch-success', {
|
||||
items: unref(resultInfo),
|
||||
resultTotal
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
emit('fetch-error', error);
|
||||
dataSourceRef.value = [];
|
||||
// setPagination({
|
||||
// pageCount: 0,
|
||||
// });
|
||||
} finally {
|
||||
setLoading(false);
|
||||
const getDataSourceRef = computed(() => {
|
||||
const dataSource = unref(dataSourceRef);
|
||||
if (!dataSource || dataSource.length === 0) {
|
||||
return unref(dataSourceRef);
|
||||
}
|
||||
return unref(dataSourceRef);
|
||||
});
|
||||
|
||||
async function fetch(opt?) {
|
||||
try {
|
||||
setLoading(true);
|
||||
const { request, pagination }: any = unref(propsRef);
|
||||
|
||||
//组装分页信息
|
||||
const pageField = APISETTING.pageField;
|
||||
const sizeField = APISETTING.sizeField;
|
||||
const totalField = APISETTING.totalField;
|
||||
const listField = APISETTING.listField;
|
||||
|
||||
let pageParams = {};
|
||||
const { page = 1, pageSize = 10 } = unref(getPaginationInfo) as PaginationProps;
|
||||
|
||||
if ((isBoolean(pagination) && !pagination) || isBoolean(getPaginationInfo)) {
|
||||
pageParams = {};
|
||||
} else {
|
||||
pageParams[pageField] = (opt && opt[pageField]) || page;
|
||||
pageParams[sizeField] = pageSize;
|
||||
}
|
||||
|
||||
const params = {
|
||||
...pageParams,
|
||||
};
|
||||
const res = await request(params);
|
||||
|
||||
const resultTotal = res[totalField] || 0;
|
||||
const currentPage = res[pageField];
|
||||
|
||||
// 如果数据异常,需获取正确的页码再次执行
|
||||
if (resultTotal) {
|
||||
const currentTotalPage = Math.ceil(resultTotal / pageSize);
|
||||
if (page > currentTotalPage) {
|
||||
setPagination({
|
||||
[pageField]: currentTotalPage,
|
||||
});
|
||||
fetch(opt);
|
||||
}
|
||||
}
|
||||
const resultInfo = res[listField] ? res[listField] : [];
|
||||
dataSourceRef.value = resultInfo;
|
||||
setPagination({
|
||||
[pageField]: currentPage,
|
||||
[totalField]: resultTotal,
|
||||
});
|
||||
if (opt && opt[pageField]) {
|
||||
setPagination({
|
||||
[pageField]: opt[pageField] || 1,
|
||||
});
|
||||
}
|
||||
emit('fetch-success', {
|
||||
items: unref(resultInfo),
|
||||
resultTotal,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
emit('fetch-error', error);
|
||||
dataSourceRef.value = [];
|
||||
// setPagination({
|
||||
// pageCount: 0,
|
||||
// });
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
setTimeout(() => {
|
||||
fetch();
|
||||
}, 16)
|
||||
});
|
||||
onMounted(() => {
|
||||
setTimeout(() => {
|
||||
fetch();
|
||||
}, 16);
|
||||
});
|
||||
|
||||
function setTableData(values) {
|
||||
dataSourceRef.value = values;
|
||||
}
|
||||
function setTableData(values) {
|
||||
dataSourceRef.value = values;
|
||||
}
|
||||
|
||||
function getDataSource(): any[] {
|
||||
return getDataSourceRef.value;
|
||||
}
|
||||
function getDataSource(): any[] {
|
||||
return getDataSourceRef.value;
|
||||
}
|
||||
|
||||
async function reload(opt?) {
|
||||
await fetch(opt);
|
||||
}
|
||||
async function reload(opt?) {
|
||||
await fetch(opt);
|
||||
}
|
||||
|
||||
return {
|
||||
fetch,
|
||||
getRowKey,
|
||||
getDataSourceRef,
|
||||
getDataSource,
|
||||
setTableData,
|
||||
reload
|
||||
}
|
||||
return {
|
||||
fetch,
|
||||
getRowKey,
|
||||
getDataSourceRef,
|
||||
getDataSource,
|
||||
setTableData,
|
||||
reload,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,20 +2,20 @@ import { ref, ComputedRef, unref, computed, watch } from 'vue';
|
||||
import type { BasicTableProps } from '../types/table';
|
||||
|
||||
export function useLoading(props: ComputedRef<BasicTableProps>) {
|
||||
const loadingRef = ref(unref(props).loading);
|
||||
const loadingRef = ref(unref(props).loading);
|
||||
|
||||
watch(
|
||||
() => unref(props).loading,
|
||||
(loading) => {
|
||||
loadingRef.value = loading;
|
||||
}
|
||||
);
|
||||
|
||||
const getLoading = computed(() => unref(loadingRef));
|
||||
|
||||
function setLoading(loading: boolean) {
|
||||
loadingRef.value = loading;
|
||||
watch(
|
||||
() => unref(props).loading,
|
||||
(loading) => {
|
||||
loadingRef.value = loading;
|
||||
}
|
||||
);
|
||||
|
||||
return { getLoading, setLoading };
|
||||
const getLoading = computed(() => unref(loadingRef));
|
||||
|
||||
function setLoading(loading: boolean) {
|
||||
loadingRef.value = loading;
|
||||
}
|
||||
|
||||
return { getLoading, setLoading };
|
||||
}
|
||||
|
||||
@@ -6,43 +6,43 @@ import { isBoolean } from '@/utils/is';
|
||||
import { DEFAULTPAGESIZE, PAGESIZES } from '../const';
|
||||
|
||||
export function usePagination(refProps: ComputedRef<BasicTableProps>) {
|
||||
const configRef = ref<PaginationProps>({});
|
||||
const show = ref(true);
|
||||
const configRef = ref<PaginationProps>({});
|
||||
const show = ref(true);
|
||||
|
||||
const getPaginationInfo = computed((): PaginationProps | boolean => {
|
||||
const { pagination } = unref(refProps);
|
||||
if (!unref(show) || (isBoolean(pagination) && !pagination)) {
|
||||
return false;
|
||||
}
|
||||
return {
|
||||
pageSize: DEFAULTPAGESIZE,
|
||||
pageSizes: PAGESIZES,
|
||||
showSizePicker: true,
|
||||
showQuickJumper: true,
|
||||
...(isBoolean(pagination) ? {} : pagination),
|
||||
...unref(configRef),
|
||||
};
|
||||
});
|
||||
|
||||
function setPagination(info: Partial<PaginationProps>) {
|
||||
const paginationInfo = unref(getPaginationInfo);
|
||||
configRef.value = {
|
||||
...(!isBoolean(paginationInfo) ? paginationInfo : {}),
|
||||
...info,
|
||||
};
|
||||
const getPaginationInfo = computed((): PaginationProps | boolean => {
|
||||
const { pagination } = unref(refProps);
|
||||
if (!unref(show) || (isBoolean(pagination) && !pagination)) {
|
||||
return false;
|
||||
}
|
||||
return {
|
||||
pageSize: DEFAULTPAGESIZE,
|
||||
pageSizes: PAGESIZES,
|
||||
showSizePicker: true,
|
||||
showQuickJumper: true,
|
||||
...(isBoolean(pagination) ? {} : pagination),
|
||||
...unref(configRef),
|
||||
};
|
||||
});
|
||||
|
||||
function getPagination() {
|
||||
return unref(getPaginationInfo);
|
||||
}
|
||||
function setPagination(info: Partial<PaginationProps>) {
|
||||
const paginationInfo = unref(getPaginationInfo);
|
||||
configRef.value = {
|
||||
...(!isBoolean(paginationInfo) ? paginationInfo : {}),
|
||||
...info,
|
||||
};
|
||||
}
|
||||
|
||||
function getShowPagination() {
|
||||
return unref(show);
|
||||
}
|
||||
function getPagination() {
|
||||
return unref(getPaginationInfo);
|
||||
}
|
||||
|
||||
async function setShowPagination(flag: boolean) {
|
||||
show.value = flag;
|
||||
}
|
||||
function getShowPagination() {
|
||||
return unref(show);
|
||||
}
|
||||
|
||||
return { getPagination, getPaginationInfo, setShowPagination, getShowPagination, setPagination };
|
||||
async function setShowPagination(flag: boolean) {
|
||||
show.value = flag;
|
||||
}
|
||||
|
||||
return { getPagination, getPaginationInfo, setShowPagination, getShowPagination, setPagination };
|
||||
}
|
||||
|
||||
@@ -5,18 +5,18 @@ import { provide, inject, ComputedRef } from 'vue';
|
||||
const key = Symbol('s-table');
|
||||
|
||||
type Instance = TableActionType & {
|
||||
wrapRef: Ref<Nullable<HTMLElement>>;
|
||||
getBindValues: ComputedRef<Recordable>;
|
||||
wrapRef: Ref<Nullable<HTMLElement>>;
|
||||
getBindValues: ComputedRef<Recordable>;
|
||||
};
|
||||
|
||||
type RetInstance = Omit<Instance, 'getBindValues'> & {
|
||||
getBindValues: ComputedRef<BasicTableProps>;
|
||||
getBindValues: ComputedRef<BasicTableProps>;
|
||||
};
|
||||
|
||||
export function createTableContext(instance: Instance) {
|
||||
provide(key, instance);
|
||||
provide(key, instance);
|
||||
}
|
||||
|
||||
export function useTableContext(): RetInstance {
|
||||
return inject(key) as RetInstance;
|
||||
return inject(key) as RetInstance;
|
||||
}
|
||||
|
||||
@@ -1,49 +1,47 @@
|
||||
import type { PropType } from 'vue'
|
||||
import { BasicColumn } from './types/table'
|
||||
import type { PropType } from 'vue';
|
||||
import { BasicColumn } from './types/table';
|
||||
|
||||
export const basicProps = {
|
||||
title: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
titleTooltip: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: 'medium',
|
||||
},
|
||||
tableData: {
|
||||
type: [Object],
|
||||
default: () => {
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
type: [Array] as PropType<BasicColumn[]>,
|
||||
default: () => [],
|
||||
required: true,
|
||||
},
|
||||
request: {
|
||||
type: Function as PropType<(...arg: any[]) => Promise<any>>,
|
||||
default: null,
|
||||
required: true
|
||||
},
|
||||
rowKey: {
|
||||
type: [String, Function] as PropType<string | ((record) => string)>,
|
||||
default: undefined,
|
||||
},
|
||||
pagination: {
|
||||
type: [Object, Boolean],
|
||||
default: () => {
|
||||
}
|
||||
},
|
||||
showPagination: {
|
||||
type: [String, Boolean],
|
||||
default: 'auto'
|
||||
},
|
||||
actionColumn: {
|
||||
type: Object as PropType<BasicColumn>,
|
||||
default: null,
|
||||
},
|
||||
}
|
||||
title: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
titleTooltip: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: 'medium',
|
||||
},
|
||||
tableData: {
|
||||
type: [Object],
|
||||
default: () => {},
|
||||
},
|
||||
columns: {
|
||||
type: [Array] as PropType<BasicColumn[]>,
|
||||
default: () => [],
|
||||
required: true,
|
||||
},
|
||||
request: {
|
||||
type: Function as PropType<(...arg: any[]) => Promise<any>>,
|
||||
default: null,
|
||||
required: true,
|
||||
},
|
||||
rowKey: {
|
||||
type: [String, Function] as PropType<string | ((record) => string)>,
|
||||
default: undefined,
|
||||
},
|
||||
pagination: {
|
||||
type: [Object, Boolean],
|
||||
default: () => {},
|
||||
},
|
||||
showPagination: {
|
||||
type: [String, Boolean],
|
||||
default: 'auto',
|
||||
},
|
||||
actionColumn: {
|
||||
type: Object as PropType<BasicColumn>,
|
||||
default: null,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import Pagination from 'naive-ui/lib/pagination';
|
||||
import { VNodeChild } from 'vue';
|
||||
|
||||
export interface PaginationProps {
|
||||
page?: number;
|
||||
pageCount?: number,
|
||||
pageSize?: number,
|
||||
pageSizes?: number[],
|
||||
showSizePicker?: boolean,
|
||||
showQuickJumper?: boolean,
|
||||
page?: number;
|
||||
pageCount?: number;
|
||||
pageSize?: number;
|
||||
pageSizes?: number[];
|
||||
showSizePicker?: boolean;
|
||||
showQuickJumper?: boolean;
|
||||
}
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
import type {
|
||||
TableBaseColumn,
|
||||
} from 'naive-ui/lib/data-table/src/interface';
|
||||
import type { TableBaseColumn } from 'naive-ui/lib/data-table/src/interface';
|
||||
|
||||
export interface BasicColumn extends TableBaseColumn {
|
||||
|
||||
}
|
||||
export type BasicColumn = TableBaseColumn;
|
||||
|
||||
export interface TableActionType {
|
||||
reload: (opt) => Promise<void>;
|
||||
emit?: any;
|
||||
getColumns: (opt) => BasicColumn[];
|
||||
setColumns: (columns: BasicColumn[] | string[]) => void;
|
||||
reload: (opt) => Promise<void>;
|
||||
emit?: any;
|
||||
getColumns: (opt?) => BasicColumn[];
|
||||
setColumns: (columns: BasicColumn[] | string[]) => void;
|
||||
}
|
||||
|
||||
export interface BasicTableProps<T = any> {
|
||||
title?: string,
|
||||
dataSource: Function,
|
||||
columns: any[],
|
||||
pagination: object,
|
||||
showPagination: boolean
|
||||
export interface BasicTableProps {
|
||||
title?: string;
|
||||
dataSource: Function;
|
||||
columns: any[];
|
||||
pagination: object;
|
||||
showPagination: boolean;
|
||||
actionColumn: any[];
|
||||
}
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
import { NButton, NTooltip } from 'naive-ui';
|
||||
import { RoleEnum } from '/@/enums/roleEnum';
|
||||
|
||||
// @ts-ignore
|
||||
import { NButton } from 'naive-ui';
|
||||
import { RoleEnum } from '@/enums/roleEnum';
|
||||
// @ts-ignore
|
||||
export interface ActionItem extends NButton.props {
|
||||
onClick?: Fn;
|
||||
label?: string;
|
||||
color?: 'success' | 'error' | 'warning';
|
||||
icon?: string;
|
||||
popConfirm?: PopConfirm;
|
||||
disabled?: boolean;
|
||||
divider?: boolean;
|
||||
// 权限编码控制是否显示
|
||||
auth?: RoleEnum | RoleEnum[] | string | string[];
|
||||
// 业务控制是否显示
|
||||
ifShow?: boolean | ((action: ActionItem) => boolean);
|
||||
tooltip?: string | TooltipProps;
|
||||
onClick?: Fn;
|
||||
label?: string;
|
||||
color?: 'success' | 'error' | 'warning';
|
||||
icon?: string;
|
||||
popConfirm?: PopConfirm;
|
||||
disabled?: boolean;
|
||||
divider?: boolean;
|
||||
// 权限编码控制是否显示
|
||||
auth?: RoleEnum | RoleEnum[] | string | string[];
|
||||
// 业务控制是否显示
|
||||
ifShow?: boolean | ((action: ActionItem) => boolean);
|
||||
}
|
||||
|
||||
export interface PopConfirm {
|
||||
title: string;
|
||||
okText?: string;
|
||||
cancelText?: string;
|
||||
confirm: Fn;
|
||||
cancel?: Fn;
|
||||
icon?: string;
|
||||
title: string;
|
||||
okText?: string;
|
||||
cancelText?: string;
|
||||
confirm: Fn;
|
||||
cancel?: Fn;
|
||||
icon?: string;
|
||||
}
|
||||
|
||||
@@ -2,42 +2,48 @@
|
||||
<div class="w-full">
|
||||
<div class="upload">
|
||||
<div class="upload-card">
|
||||
|
||||
<!--图片列表-->
|
||||
<div class="upload-card-item" :style="getCSSProperties" v-for="(item,index) in imgList">
|
||||
<div
|
||||
class="upload-card-item"
|
||||
:style="getCSSProperties"
|
||||
v-for="(item, index) in imgList"
|
||||
:key="`img_${index}`"
|
||||
>
|
||||
<div class="upload-card-item-info">
|
||||
<div class="img-box">
|
||||
<img :src="item"/>
|
||||
<img :src="item" />
|
||||
</div>
|
||||
<div class="img-box-actions">
|
||||
<n-icon size="18" class="action-icon mx-2" @click="preview(item)">
|
||||
<EyeOutlined/>
|
||||
<EyeOutlined />
|
||||
</n-icon>
|
||||
<n-icon size="18" class="action-icon mx-2" @click="remove(index)">
|
||||
<DeleteOutlined/>
|
||||
<DeleteOutlined />
|
||||
</n-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--上传图片-->
|
||||
<div class="upload-card-item upload-card-item-select-picture" :style="getCSSProperties"
|
||||
v-if="imgList.length < maxNumber">
|
||||
<div
|
||||
class="upload-card-item upload-card-item-select-picture"
|
||||
:style="getCSSProperties"
|
||||
v-if="imgList.length < maxNumber"
|
||||
>
|
||||
<n-upload
|
||||
v-bind="$props"
|
||||
:file-list-style="{ display:'none'}"
|
||||
@before-upload="beforeUpload"
|
||||
@finish="finish"
|
||||
v-bind="$props"
|
||||
:file-list-style="{ display: 'none' }"
|
||||
@before-upload="beforeUpload"
|
||||
@finish="finish"
|
||||
>
|
||||
<div class="flex justify-center flex-col">
|
||||
<n-icon size="18" class="m-auto">
|
||||
<PlusOutlined/>
|
||||
<PlusOutlined />
|
||||
</n-icon>
|
||||
<span class="upload-title">上传图片</span>
|
||||
</div>
|
||||
</n-upload>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -47,267 +53,254 @@
|
||||
{{ helpText }}
|
||||
</n-alert>
|
||||
</n-space>
|
||||
|
||||
</div>
|
||||
|
||||
<!--预览图片-->
|
||||
<n-modal
|
||||
v-model:show="showModal"
|
||||
preset="card"
|
||||
title="预览"
|
||||
:bordered="false"
|
||||
:style="{width: '520px'}"
|
||||
v-model:show="showModal"
|
||||
preset="card"
|
||||
title="预览"
|
||||
:bordered="false"
|
||||
:style="{ width: '520px' }"
|
||||
>
|
||||
<img :src="previewUrl"/>
|
||||
<img :src="previewUrl" />
|
||||
</n-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, toRefs, reactive, computed } from "vue";
|
||||
import { EyeOutlined, DeleteOutlined, PlusOutlined } from "@vicons/antd";
|
||||
import { NUpload } from 'naive-ui'
|
||||
import { basicProps } from "./props";
|
||||
import { useMessage, useDialog } from 'naive-ui'
|
||||
import { ResultEnum } from '@/enums/httpEnum'
|
||||
import componentSetting from '@/settings/componentSetting'
|
||||
import { useGlobSetting } from '@/hooks/setting'
|
||||
import { isString } from '@/utils/is'
|
||||
import { defineComponent, toRefs, reactive, computed } from 'vue';
|
||||
import { EyeOutlined, DeleteOutlined, PlusOutlined } from '@vicons/antd';
|
||||
import { NUpload } from 'naive-ui';
|
||||
import { basicProps } from './props';
|
||||
import { useMessage, useDialog } from 'naive-ui';
|
||||
import { ResultEnum } from '@/enums/httpEnum';
|
||||
import componentSetting from '@/settings/componentSetting';
|
||||
import { useGlobSetting } from '@/hooks/setting';
|
||||
import { isString } from '@/utils/is';
|
||||
|
||||
const globSetting = useGlobSetting()
|
||||
const globSetting = useGlobSetting();
|
||||
|
||||
export default defineComponent({
|
||||
name: 'BasicUpload',
|
||||
export default defineComponent({
|
||||
name: 'BasicUpload',
|
||||
|
||||
components: { EyeOutlined, DeleteOutlined, PlusOutlined },
|
||||
props: {
|
||||
...NUpload.props, // 这里继承原 UI 组件的 props
|
||||
...basicProps
|
||||
},
|
||||
emits: ['uploadChange', 'delete'],
|
||||
setup(props, { emit }) {
|
||||
const { value, width, height } = props
|
||||
components: { EyeOutlined, DeleteOutlined, PlusOutlined },
|
||||
props: {
|
||||
...NUpload.props, // 这里继承原 UI 组件的 props
|
||||
...basicProps,
|
||||
},
|
||||
emits: ['uploadChange', 'delete'],
|
||||
setup(props, { emit }) {
|
||||
const getCSSProperties = computed(() => {
|
||||
return {
|
||||
width: `${props.width}px`,
|
||||
height: `${props.height}px`,
|
||||
};
|
||||
});
|
||||
|
||||
const getCSSProperties = computed(() => {
|
||||
return {
|
||||
width: `${ width }px`,
|
||||
height: `${ height }px`,
|
||||
const message = useMessage();
|
||||
const dialog = useDialog();
|
||||
|
||||
const state = reactive({
|
||||
showModal: false,
|
||||
previewUrl: '',
|
||||
originalImgList: [],
|
||||
imgList: [],
|
||||
});
|
||||
|
||||
//赋值默认图片显示
|
||||
if (props.value.length) {
|
||||
state.imgList = props.value.map((item) => {
|
||||
return getImgUrl(item);
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
const message = useMessage()
|
||||
const dialog = useDialog()
|
||||
//预览
|
||||
function preview(url: string) {
|
||||
state.showModal = true;
|
||||
state.previewUrl = url;
|
||||
}
|
||||
|
||||
const state = reactive({
|
||||
showModal: false,
|
||||
previewUrl: '',
|
||||
originalImgList: [],
|
||||
imgList: []
|
||||
})
|
||||
//删除
|
||||
function remove(index: number) {
|
||||
dialog.info({
|
||||
title: '提示',
|
||||
content: '你确定要删除吗?',
|
||||
positiveText: '确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
state.imgList.splice(index, 1);
|
||||
state.originalImgList.splice(index, 1);
|
||||
emit('uploadChange', state.originalImgList);
|
||||
emit('delete', state.originalImgList);
|
||||
},
|
||||
onNegativeClick: () => {},
|
||||
});
|
||||
}
|
||||
|
||||
//赋值默认图片显示
|
||||
if (value.length) {
|
||||
state.imgList = value.map(item => {
|
||||
return getImgUrl(item)
|
||||
})
|
||||
}
|
||||
//组装完整图片地址
|
||||
function getImgUrl(url: string): string {
|
||||
const { imgUrl } = globSetting;
|
||||
return /(^http|https:\/\/)/g.test(url) ? url : `${imgUrl}${url}`;
|
||||
}
|
||||
|
||||
//预览
|
||||
function preview(url: string) {
|
||||
state.showModal = true
|
||||
state.previewUrl = url
|
||||
}
|
||||
function checkFileType(fileType: string) {
|
||||
return componentSetting.upload.fileType.includes(fileType);
|
||||
}
|
||||
|
||||
//删除
|
||||
function remove(index: number) {
|
||||
dialog.info({
|
||||
title: '提示',
|
||||
content: '你确定要删除吗?',
|
||||
positiveText: '确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
state.imgList.splice(index, 1)
|
||||
state.originalImgList.splice(index, 1)
|
||||
emit('uploadChange', state.originalImgList)
|
||||
emit('delete', state.originalImgList)
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
//上传之前
|
||||
function beforeUpload({ file }) {
|
||||
const fileInfo = file.file;
|
||||
const { maxSize, accept } = props;
|
||||
const acceptRef = (isString(accept) && accept.split(',')) || [];
|
||||
|
||||
// 设置最大值,则判断
|
||||
if (maxSize && fileInfo.size / 1024 / 1024 >= maxSize) {
|
||||
message.error(`上传文件最大值不能超过${maxSize}M`);
|
||||
return false;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//组装完整图片地址
|
||||
function getImgUrl(url: string) {
|
||||
const { imgUrl } = globSetting
|
||||
return (/(^http|https:\/\/)/g).test(url) ? url : `${ imgUrl }${ url }`
|
||||
}
|
||||
// 设置类型,则判断
|
||||
const fileType = componentSetting.upload.fileType;
|
||||
if (acceptRef.length > 0 && !checkFileType(fileInfo.type)) {
|
||||
message.error(`只能上传文件类型为${fileType.join(',')}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function checkFileType(fileType: string) {
|
||||
return componentSetting.upload.fileType.includes(fileType)
|
||||
}
|
||||
|
||||
//上传之前
|
||||
function beforeUpload({ file, fileList }) {
|
||||
const fileInfo = file.file;
|
||||
const { maxSize, accept, maxNumber } = props;
|
||||
const acceptRef = (isString(accept) && accept.split(',')) || [];
|
||||
|
||||
// 设置最大值,则判断
|
||||
if (maxSize && fileInfo.size / 1024 / 1024 >= maxSize) {
|
||||
message.error(`上传文件最大值不能超过${ maxSize }M`);
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 设置类型,则判断
|
||||
const fileType = componentSetting.upload.fileType
|
||||
if (acceptRef.length > 0 && !checkFileType(fileInfo.type)) {
|
||||
message.error(`只能上传文件类型为${ fileType.join(',') }`);
|
||||
return false;
|
||||
//上传结束
|
||||
function finish({ event: Event }) {
|
||||
const res = eval('(' + Event.target.response + ')');
|
||||
const infoField = componentSetting.upload.apiSetting.infoField;
|
||||
const { code } = res;
|
||||
const message = res.msg || res.message || '上传失败';
|
||||
const result = res[infoField];
|
||||
//成功
|
||||
if (code === ResultEnum.SUCCESS) {
|
||||
let imgUrl = getImgUrl(result.photo);
|
||||
state.imgList.push(imgUrl);
|
||||
state.originalImgList.push(result.photo);
|
||||
emit('uploadChange', state.originalImgList);
|
||||
} else message.error(message);
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
//上传结束
|
||||
function finish({ event: Event }) {
|
||||
const res = eval('(' + Event.target.response + ')');
|
||||
const infoField = componentSetting.upload.apiSetting.infoField
|
||||
const { code } = res
|
||||
const message = (res.msg || res.message) || '上传失败'
|
||||
const result = res[infoField]
|
||||
//成功
|
||||
if (code === ResultEnum.SUCCESS) {
|
||||
let imgUrl: string = getImgUrl(result.photo)
|
||||
state.imgList.push(imgUrl)
|
||||
state.originalImgList.push(result.photo)
|
||||
emit('uploadChange', state.originalImgList)
|
||||
} else message.error(message)
|
||||
}
|
||||
|
||||
return {
|
||||
...toRefs(state),
|
||||
finish,
|
||||
preview,
|
||||
remove,
|
||||
beforeUpload,
|
||||
getCSSProperties
|
||||
}
|
||||
}
|
||||
})
|
||||
return {
|
||||
...toRefs(state),
|
||||
finish,
|
||||
preview,
|
||||
remove,
|
||||
beforeUpload,
|
||||
getCSSProperties,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.upload {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
.upload {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
&-card {
|
||||
width: auto;
|
||||
height: auto;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
|
||||
&-item {
|
||||
margin: 0 8px 8px 0;
|
||||
position: relative;
|
||||
padding: 8px;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 2px;
|
||||
&-card {
|
||||
width: auto;
|
||||
height: auto;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
|
||||
&:hover {
|
||||
background: 0 0;
|
||||
|
||||
&-info::before {
|
||||
opacity: 1
|
||||
}
|
||||
}
|
||||
|
||||
&-info {
|
||||
&-item {
|
||||
margin: 0 8px 8px 0;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
padding: 8px;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 2px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
&:hover {
|
||||
.img-box-actions {
|
||||
background: 0 0;
|
||||
.upload-card-item-info::before {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&-info::before {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, .5);
|
||||
opacity: 0;
|
||||
transition: all .3s;
|
||||
content: ' ';
|
||||
}
|
||||
|
||||
.img-box {
|
||||
&-info {
|
||||
position: relative;
|
||||
//padding: 8px;
|
||||
//border: 1px solid #d9d9d9;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.img-box-actions {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
z-index: 10;
|
||||
white-space: nowrap;
|
||||
transform: translate(-50%, -50%);
|
||||
opacity: 0;
|
||||
transition: all .3s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
|
||||
&:hover {
|
||||
background: 0 0;
|
||||
.img-box-actions {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.action-icon {
|
||||
color: rgba(255, 255, 255, .85);
|
||||
&::before {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
opacity: 0;
|
||||
transition: all 0.3s;
|
||||
content: ' ';
|
||||
}
|
||||
|
||||
.img-box {
|
||||
position: relative;
|
||||
//padding: 8px;
|
||||
//border: 1px solid #d9d9d9;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.img-box-actions {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
z-index: 10;
|
||||
white-space: nowrap;
|
||||
transform: translate(-50%, -50%);
|
||||
opacity: 0;
|
||||
transition: all 0.3s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
color: #fff
|
||||
background: 0 0;
|
||||
}
|
||||
|
||||
.action-icon {
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&-item-select-picture {
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
background: #fafafa;
|
||||
color: #666;
|
||||
|
||||
.upload-title {
|
||||
&-item-select-picture {
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
background: #fafafa;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
&-item:hover {
|
||||
background: 0 0;
|
||||
|
||||
.upload-card-item-info::before {
|
||||
opacity: 1
|
||||
.upload-title {
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
import type { PropType } from 'vue'
|
||||
import { NUpload } from 'naive-ui'
|
||||
import type { PropType } from 'vue';
|
||||
import { NUpload } from 'naive-ui';
|
||||
|
||||
export const basicProps = {
|
||||
...NUpload.props,
|
||||
accept: {
|
||||
type: String,
|
||||
default: '.jpg,.png,.jpeg,.svg,.gif',
|
||||
},
|
||||
helpText: {
|
||||
type: String as PropType<string>,
|
||||
default: '',
|
||||
},
|
||||
maxSize: {
|
||||
type: Number as PropType<number>,
|
||||
default: 2
|
||||
},
|
||||
maxNumber: {
|
||||
type: Number as PropType<number>,
|
||||
default: Infinity
|
||||
},
|
||||
value: {
|
||||
type: Array as PropType<string[]>,
|
||||
default: () => []
|
||||
},
|
||||
width: {
|
||||
type: Number as PropType<number>,
|
||||
default: 104
|
||||
},
|
||||
height: {
|
||||
type: Number as PropType<number>,
|
||||
default: 104 //建议不小于这个尺寸 太小页面可能显示有异常
|
||||
},
|
||||
}
|
||||
...NUpload.props,
|
||||
accept: {
|
||||
type: String,
|
||||
default: '.jpg,.png,.jpeg,.svg,.gif',
|
||||
},
|
||||
helpText: {
|
||||
type: String as PropType<string>,
|
||||
default: '',
|
||||
},
|
||||
maxSize: {
|
||||
type: Number as PropType<number>,
|
||||
default: 2,
|
||||
},
|
||||
maxNumber: {
|
||||
type: Number as PropType<number>,
|
||||
default: Infinity,
|
||||
},
|
||||
value: {
|
||||
type: Array as PropType<string[]>,
|
||||
default: () => [],
|
||||
},
|
||||
width: {
|
||||
type: Number as PropType<number>,
|
||||
default: 104,
|
||||
},
|
||||
height: {
|
||||
type: Number as PropType<number>,
|
||||
default: 104, //建议不小于这个尺寸 太小页面可能显示有异常
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export interface BasicProps<T = any> {
|
||||
title?: string,
|
||||
dataSource: Function,
|
||||
columns: any[],
|
||||
pagination: object,
|
||||
showPagination: boolean
|
||||
export interface BasicProps {
|
||||
title?: string;
|
||||
dataSource: Function;
|
||||
columns: any[];
|
||||
pagination: object;
|
||||
showPagination: boolean;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user