Merge branch 'master' of gitee.com:yudaocode/yudao-ui-admin-vue3 into master-iotscene

Signed-off-by: 熊猫大侠 <1565636758@qq.com>
pull/880/head
熊猫大侠 2026-05-26 06:02:26 +00:00 committed by Gitee
commit c8b132433a
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
124 changed files with 922 additions and 752 deletions

View File

@ -215,8 +215,8 @@ export const ThingModelFormRules = {
identifier: [
{ required: true, message: '标识符不能为空', trigger: 'blur' },
{
pattern: /^[a-zA-Z0-9_]{1,50}$/,
message: '支持大小写字母、数字和下划线,不超过 50 个字符',
pattern: /^[a-zA-Z][a-zA-Z0-9_]{0,31}$/,
message: '支持大小写字母、数字和下划线,必须以字母开头,不超过 32 个字符',
trigger: 'blur'
},
{

View File

@ -6,6 +6,7 @@ export interface ProAndonConfigVO {
reason: string // 呼叫原因
level: number // 级别
handlerRoleId: number // 处置人角色编号
handlerRoleName: string // 处置人角色名称
handlerUserId: number // 处置人编号
handlerUserNickname: string // 处置人昵称
remark: string // 备注

View File

@ -116,7 +116,8 @@ const toggleClick = () => {
:row="{
label: item.label
}"
>{{ item.label }}
>
{{ item.label }}
</slot>
</template>
@ -130,9 +131,7 @@ const toggleClick = () => {
<DictTag :type="item.dictType" :value="data[item.field] + ''" />
</slot>
<slot v-else :name="item.field" :row="data">
{{
item.mappedField ? data[item.mappedField] : data[item.field]
}}
{{ item.mappedField ? data[item.mappedField] : data[item.field] }}
</slot>
</template>
</ElDescriptionsItem>

View File

@ -165,8 +165,8 @@ $toolbar-position: -55px;
width: 80px;
height: 25px;
font-size: 12px;
color: #6a6a6a;
line-height: 25px;
color: #6a6a6a;
text-align: center;
background: #fff;
box-shadow:

View File

@ -94,9 +94,9 @@ const handleCloneComponent = (component: DiyComponent<any>) => {
<style scoped lang="scss">
.editor-left {
z-index: 1;
flex-shrink: 0;
user-select: none;
box-shadow: 8px 0 8px -8px rgb(0 0 0 / 12%);
user-select: none;
flex-shrink: 0;
:deep(.el-collapse) {
border-top: none;

View File

@ -22,8 +22,9 @@
<div
v-if="property.indicator === 'number'"
class="absolute bottom-10px right-10px rounded-xl bg-black p-x-8px p-y-2px text-10px text-white opacity-40"
>{{ currentIndex }} / {{ property.items.length }}</div
>
{{ currentIndex }} / {{ property.items.length }}
</div>
</div>
</template>
<script setup lang="ts">

View File

@ -55,12 +55,12 @@ const handleToggleFab = () => {
/* 模态背景 */
.modal-bg {
position: absolute;
left: calc(50% - 375px / 2);
top: 0;
left: calc(50% - 375px / 2);
z-index: 11;
width: 375px;
height: 100%;
background-color: rgba(#000000, 0.4);
background-color: rgb(0 0 0 / 40%);
}
.fab-icon {

View File

@ -192,39 +192,39 @@ const handleAppLinkChange = (appLink: AppLink) => {
<style scoped lang="scss">
.hot-zone {
position: absolute;
background: var(--el-color-primary-light-7);
opacity: 0.8;
border: 1px solid var(--el-color-primary);
color: var(--el-color-primary);
font-size: 16px;
z-index: 10;
display: flex;
font-size: 16px;
color: var(--el-color-primary);
cursor: move;
background: var(--el-color-primary-light-7);
border: 1px solid var(--el-color-primary);
opacity: 0.8;
align-items: center;
justify-content: center;
cursor: move;
z-index: 10;
/* 控制点 */
.ctrl-dot {
position: absolute;
z-index: 11;
width: 8px;
height: 8px;
border-radius: 50%;
border: inherit;
background-color: #fff;
z-index: 11;
border: inherit;
border-radius: 50%;
}
.delete {
display: none;
position: absolute;
top: 0;
right: 0;
display: none;
padding: 2px 2px 6px 6px;
background-color: var(--el-color-primary);
border-radius: 0 0 0 80%;
cursor: pointer;
color: #fff;
text-align: right;
cursor: pointer;
background-color: var(--el-color-primary);
border-radius: 0 0 0 80%;
}
&:hover {

View File

@ -28,15 +28,15 @@ const props = defineProps<{ property: HotZoneProperty }>()
<style scoped lang="scss">
.hot-zone {
position: absolute;
background: var(--el-color-primary-light-7);
opacity: 0.8;
border: 1px solid var(--el-color-primary);
color: var(--el-color-primary);
font-size: 14px;
z-index: 10;
display: flex;
font-size: 14px;
color: var(--el-color-primary);
cursor: move;
background: var(--el-color-primary-light-7);
border: 1px solid var(--el-color-primary);
opacity: 0.8;
align-items: center;
justify-content: center;
cursor: move;
z-index: 10;
}
</style>

View File

@ -42,22 +42,22 @@ const handleOpenEditDialog = () => {
<style scoped lang="scss">
.hot-zone {
position: absolute;
display: flex;
font-size: 12px;
color: #fff;
cursor: move;
background: #409effbf;
border: 1px solid var(--el-color-primary);
color: #fff;
font-size: 12px;
display: flex;
align-items: center;
justify-content: center;
cursor: move;
/* 控制点 */
.ctrl-dot {
position: absolute;
width: 4px;
height: 4px;
border-radius: 50%;
background-color: #fff;
border-radius: 50%;
}
}
</style>

View File

@ -39,7 +39,7 @@
</span>
</div>
</div>
</el-carousel-item>
</el-carousel-item>
</el-carousel>
</template>
@ -103,13 +103,16 @@ watch(
.el-carousel__indicator {
padding-top: 0;
padding-bottom: 0;
.el-carousel__button {
--el-carousel-indicator-height: 6px;
--el-carousel-indicator-width: 6px;
--el-carousel-indicator-out-color: #ff6000;
border-radius: 6px;
}
}
.el-carousel__indicator.is-active {
.el-carousel__button {
--el-carousel-indicator-width: 12px;

View File

@ -93,8 +93,8 @@ defineOptions({ name: 'NavigationBarCellProperty' })
const props = withDefaults(
defineProps<{
modelValue: NavigationBarCellProperty[]
isMp: boolean
modelValue?: NavigationBarCellProperty[]
isMp?: boolean
}>(),
{
modelValue: () => [],

View File

@ -67,10 +67,10 @@ const getSearchProp = computed(() => (cell: NavigationBarCellProperty) => {
.navigation-bar {
display: flex;
height: 50px;
padding: 0 6px;
background: #fff;
justify-content: space-between;
align-items: center;
padding: 0 6px;
/* 左边 */
.left {

View File

@ -77,7 +77,8 @@
v-if="property.fields.marketPrice.show && spu.marketPrice"
class="ml-4px text-10px line-through"
:style="{ color: property.fields.marketPrice.color }"
>{{ fenToYuan(spu.marketPrice) }}
>
{{ fenToYuan(spu.marketPrice) }}
</span>
</div>
<div class="text-12px">

View File

@ -74,8 +74,9 @@
v-if="property.fields.marketPrice.show && spu.marketPrice"
class="ml-4px text-10px line-through"
:style="{ color: property.fields.marketPrice.color }"
>{{ fenToYuan(spu.marketPrice) }}</span
>
{{ fenToYuan(spu.marketPrice) }}
</span>
</div>
<div class="text-12px">
<!-- 销量 -->

View File

@ -74,8 +74,9 @@
v-if="property.fields.marketPrice.show && spu.marketPrice"
class="ml-4px text-10px line-through"
:style="{ color: property.fields.marketPrice.color }"
>{{ fenToYuan(spu.marketPrice) }}</span
>
{{ fenToYuan(spu.marketPrice) }}
</span>
</div>
<div class="text-12px">
<!-- 销量 -->

View File

@ -583,12 +583,12 @@ $toolbar-height: 42px;
gap: 8px;
:deep(.el-tag) {
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.1);
border: none;
box-shadow: 0 2px 8px 0 rgb(0 0 0 / 10%);
.el-tag__content {
width: 100%;
display: flex;
width: 100%;
align-items: center;
justify-content: flex-start;

View File

@ -27,7 +27,6 @@ const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('form')
export default defineComponent({
// eslint-disable-next-line vue/no-reserved-component-names
name: 'Form',
props: {
// Form

View File

@ -55,7 +55,6 @@ const displayUrl = computed(() => props.url || props.modelValue || '') // 显示
const showPreview = computed(() => {
return displayUrl.value && isUrl(displayUrl.value)
}) //
</script>
<style scoped>
@ -64,9 +63,9 @@ const showPreview = computed(() => {
}
.iframe-preview {
overflow: hidden;
border: 1px solid #dcdfe6;
border-radius: 4px;
overflow: hidden;
}
.iframe-content {
@ -76,11 +75,11 @@ const showPreview = computed(() => {
.iframe-placeholder {
display: flex;
align-items: center;
justify-content: center;
min-height: 200px;
background-color: #fafafa;
border: 1px dashed #dcdfe6;
border-radius: 4px;
background-color: #fafafa;
align-items: center;
justify-content: center;
}
</style>

View File

@ -14,7 +14,6 @@ defineProps({
title: propTypes.string.def(''),
schema: {
type: Array as PropType<Array<string | TipSchema>>,
required: true,
default: () => []
},
showIndex: propTypes.bool.def(true),

View File

@ -26,6 +26,7 @@ const { modelValue, color } = useVModels(props, emit)
<style scoped lang="scss">
:deep(.el-input-group__append) {
padding: 0;
.el-color-picker__trigger {
padding: 0;
border-left: none;

View File

@ -225,15 +225,16 @@ const eachCube = (callback: (x: number, y: number, cube: Cube) => void) => {
<style lang="scss" scoped>
.cube-table {
position: relative;
border-spacing: 0;
border-collapse: collapse;
border-spacing: 0;
.cube {
border: 1px solid var(--el-border-color);
text-align: center;
color: var(--el-text-color-secondary);
text-align: center;
cursor: pointer;
border: 1px solid var(--el-border-color);
box-sizing: border-box;
&.active {
background: var(--el-color-primary-light-9);
}
@ -242,28 +243,28 @@ const eachCube = (callback: (x: number, y: number, cube: Cube) => void) => {
.hot-area {
position: absolute;
display: flex;
color: var(--el-color-primary);
cursor: pointer;
background: var(--el-color-primary-light-8);
border: 1px solid var(--el-color-primary);
border-collapse: collapse;
border-spacing: 0;
box-sizing: border-box;
align-items: center;
justify-content: center;
border: 1px solid var(--el-color-primary);
background: var(--el-color-primary-light-8);
color: var(--el-color-primary);
box-sizing: border-box;
border-spacing: 0;
border-collapse: collapse;
cursor: pointer;
.btn-delete {
z-index: 1;
position: absolute;
top: -8px;
right: -8px;
height: 16px;
width: 16px;
z-index: 1;
display: flex;
width: 16px;
height: 16px;
background-color: #fff;
border-radius: 50%;
align-items: center;
justify-content: center;
border-radius: 50%;
background-color: #fff;
}
}
}

View File

@ -51,14 +51,14 @@ onMounted(async () => {
<style lang="scss">
.markdown-view {
font-family: PingFang SC;
max-width: 100%;
font-family: 'PingFang SC';
font-size: 0.95rem;
font-weight: 400;
line-height: 1.6rem;
letter-spacing: 0em;
text-align: left;
letter-spacing: 0;
color: #3b3e55;
max-width: 100%;
text-align: left;
pre {
position: relative;
@ -69,22 +69,23 @@ onMounted(async () => {
}
code.hljs {
border-radius: 6px;
padding-top: 20px;
width: auto;
@media screen and (min-width: 1536px) {
padding-top: 20px;
border-radius: 6px;
@media screen and (width >= 1536px) {
width: 960px;
}
@media screen and (max-width: 1536px) and (min-width: 1024px) {
@media screen and (width <= 1536px) and (width >= 1024px) {
width: calc(100vw - 400px - 64px - 32px * 2);
}
@media screen and (max-width: 1024px) and (min-width: 768px) {
@media screen and (width <= 1024px) and (width >= 768px) {
width: calc(100vw - 32px * 2);
}
@media screen and (max-width: 768px) {
@media screen and (width <= 768px) {
width: calc(100vw - 16px * 2);
}
}
@ -107,9 +108,9 @@ onMounted(async () => {
h4,
h5,
h6 {
color: var(--color-G900);
margin: 24px 0 8px;
font-weight: 600;
color: #3b3e55;
}
h1 {
@ -145,8 +146,8 @@ onMounted(async () => {
/* 列表(有序,无序) */
ul,
ol {
margin: 0 0 8px 0;
padding: 0;
margin: 0 0 8px;
font-size: 16px;
line-height: 24px;
color: #3b3e55; // var(--color-CG600);
@ -158,8 +159,8 @@ onMounted(async () => {
}
ol > li {
list-style-type: decimal;
margin-bottom: 1rem;
list-style-type: decimal;
// ,
// &:nth-child(n + 10) {
// margin-left: 30px;
@ -171,23 +172,23 @@ onMounted(async () => {
}
ul > li {
list-style-type: disc;
font-size: 16px;
line-height: 24px;
margin-right: 11px;
margin-bottom: 1rem;
font-size: 16px;
line-height: 24px;
color: #3b3e55; // var(--color-G900);
list-style-type: disc;
}
ol ul,
ol ul > li,
ul ul,
ul ul li {
margin-bottom: 1rem;
margin-left: 6px;
// list-style: circle;
font-size: 16px;
list-style: none;
margin-left: 6px;
margin-bottom: 1rem;
}
ul ul ul,

View File

@ -31,7 +31,7 @@ import { ElTag } from 'element-plus'
defineOptions({ name: 'OperateLogV2' })
interface Props {
logList: OperateLogVO[] //
logList?: OperateLogVO[] //
}
withDefaults(defineProps<Props>(), {

View File

@ -246,9 +246,9 @@ onMounted(() => {
<style lang="scss" scoped>
.simple-process-model-container {
position: relative;
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
user-select: none; //
}

View File

@ -17,18 +17,18 @@
v-model="currentNode.name"
:placeholder="currentNode.name"
/>
<div v-else class="node-name"
>{{ currentNode.name }}
<Icon class="ml-1" icon="ep:edit-pen" :size="16" @click="clickIcon()"
/></div>
<div v-else class="node-name">
{{ currentNode.name }}
<Icon class="ml-1" icon="ep:edit-pen" :size="16" @click="clickIcon()" />
</div>
<div class="divide-line"></div>
</div>
</template>
<div>
<div class="mb-3 font-size-16px" v-if="currentNode.conditionSetting?.defaultFlow"
>未满足其它条件时将进入此分支该分支不可编辑和删除</div
>
<div class="mb-3 font-size-16px" v-if="currentNode.conditionSetting?.defaultFlow">
未满足其它条件时将进入此分支该分支不可编辑和删除
</div>
<div v-else>
<Condition ref="conditionRef" v-model="condition" />
</div>

View File

@ -218,8 +218,9 @@
:value="FieldPermissionType.READ"
size="large"
:label="FieldPermissionType.WRITE"
><span></span
></el-radio>
>
<span></span>
</el-radio>
</div>
<div class="item-radio-wrap">
<el-radio
@ -227,16 +228,18 @@
size="large"
:label="FieldPermissionType.WRITE"
disabled
><span></span
></el-radio>
>
<span></span>
</el-radio>
</div>
<div class="item-radio-wrap">
<el-radio
:value="FieldPermissionType.NONE"
size="large"
:label="FieldPermissionType.NONE"
><span></span
></el-radio>
>
<span></span>
</el-radio>
</div>
</el-radio-group>
</div>

View File

@ -95,24 +95,27 @@
:value="FieldPermissionType.READ"
size="large"
:label="FieldPermissionType.READ"
><span></span
></el-radio>
>
<span></span>
</el-radio>
</div>
<div class="item-radio-wrap">
<el-radio
:value="FieldPermissionType.WRITE"
size="large"
:label="FieldPermissionType.WRITE"
><span></span
></el-radio>
>
<span></span>
</el-radio>
</div>
<div class="item-radio-wrap">
<el-radio
:value="FieldPermissionType.NONE"
size="large"
:label="FieldPermissionType.NONE"
><span></span
></el-radio>
>
<span></span>
</el-radio>
</div>
</el-radio-group>
</div>

View File

@ -414,7 +414,7 @@
<div>
<el-divider content-position="left">跳过表达式</el-divider>
<el-form-item prop="skipExpression">
<el-input v-model="configForm.skipExpression" type="textarea" />
<el-input v-model="configForm.skipExpression" type="textarea" />
</el-form-item>
</div>
</el-form>
@ -444,9 +444,9 @@
:placeholder="item.displayName"
v-if="btnDisplayNameEdit[index]"
/>
<el-button v-else text @click="changeBtnDisplayName(index)"
>{{ item.displayName }} &nbsp;<Icon icon="ep:edit"
/></el-button>
<el-button v-else text @click="changeBtnDisplayName(index)">
{{ item.displayName }} &nbsp;<Icon icon="ep:edit" />
</el-button>
</div>
<div class="button-setting-item-label">
<el-switch v-model="item.enable" />
@ -483,24 +483,27 @@
:value="FieldPermissionType.READ"
size="large"
:label="FieldPermissionType.READ"
><span></span
></el-radio>
>
<span></span>
</el-radio>
</div>
<div class="item-radio-wrap">
<el-radio
:value="FieldPermissionType.WRITE"
size="large"
:label="FieldPermissionType.WRITE"
><span></span
></el-radio>
>
<span></span>
</el-radio>
</div>
<div class="item-radio-wrap">
<el-radio
:value="FieldPermissionType.NONE"
size="large"
:label="FieldPermissionType.NONE"
><span></span
></el-radio>
>
<span></span>
</el-radio>
</div>
</el-radio-group>
</div>

View File

@ -40,9 +40,9 @@
<Icon v-if="!readonly" icon="ep:arrow-right-bold" />
</div>
<div v-if="!readonly" class="node-toolbar">
<div class="toolbar-icon"
><Icon color="#0089ff" icon="ep:circle-close-filled" :size="18" @click="deleteNode"
/></div>
<div class="toolbar-icon">
<Icon color="#0089ff" icon="ep:circle-close-filled" :size="18" @click="deleteNode" />
</div>
</div>
</div>

View File

@ -33,9 +33,9 @@
<Icon v-if="!readonly" icon="ep:arrow-right-bold" />
</div>
<div v-if="!readonly" class="node-toolbar">
<div class="toolbar-icon"
><Icon color="#0089ff" icon="ep:circle-close-filled" :size="18" @click="deleteNode"
/></div>
<div class="toolbar-icon">
<Icon color="#0089ff" icon="ep:circle-close-filled" :size="18" @click="deleteNode" />
</div>
</div>
</div>

View File

@ -33,9 +33,9 @@
<Icon v-if="!readonly" icon="ep:arrow-right-bold" />
</div>
<div v-if="!readonly" class="node-toolbar">
<div class="toolbar-icon"
><Icon color="#0089ff" icon="ep:circle-close-filled" :size="18" @click="deleteNode"
/></div>
<div class="toolbar-icon">
<Icon color="#0089ff" icon="ep:circle-close-filled" :size="18" @click="deleteNode" />
</div>
</div>
</div>

View File

@ -1,63 +1,67 @@
<template>
<div class="end-node-wrapper">
<div class="end-node-box cursor-pointer" :class="`${useTaskStatusClass(currentNode?.activityStatus)}`" @click="nodeClick">
<div
class="end-node-box cursor-pointer"
:class="`${useTaskStatusClass(currentNode?.activityStatus)}`"
@click="nodeClick"
>
<span class="node-fixed-name" title="结束">结束</span>
</div>
</div>
<el-dialog title="审批信息" v-model="dialogVisible" width="1000px" append-to-body>
<el-row>
<el-table
:data="processInstanceInfos"
size="small"
border
header-cell-class-name="table-header-gray"
>
<el-table-column
label="序号"
header-align="center"
align="center"
type="index"
width="50"
/>
<el-table-column
label="发起人"
prop="assigneeUser.nickname"
min-width="100"
align="center"
/>
<el-table-column label="部门" min-width="100" align="center">
<template #default="scope">
{{ scope.row.assigneeUser?.deptName || scope.row.ownerUser?.deptName }}
</template>
</el-table-column>
<el-table-column
:formatter="dateFormatter"
align="center"
label="开始时间"
prop="createTime"
min-width="140"
/>
<el-table-column
:formatter="dateFormatter"
align="center"
label="结束时间"
prop="endTime"
min-width="140"
/>
<el-table-column align="center" label="审批状态" prop="status" min-width="90">
<template #default="scope">
<dict-tag :type="DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column align="center" label="耗时" prop="durationInMillis" width="100">
<template #default="scope">
{{ formatPast2(scope.row.durationInMillis) }}
</template>
</el-table-column>
</el-table>
</el-row>
</el-dialog>
<el-row>
<el-table
:data="processInstanceInfos"
size="small"
border
header-cell-class-name="table-header-gray"
>
<el-table-column
label="序号"
header-align="center"
align="center"
type="index"
width="50"
/>
<el-table-column
label="发起人"
prop="assigneeUser.nickname"
min-width="100"
align="center"
/>
<el-table-column label="部门" min-width="100" align="center">
<template #default="scope">
{{ scope.row.assigneeUser?.deptName || scope.row.ownerUser?.deptName }}
</template>
</el-table-column>
<el-table-column
:formatter="dateFormatter"
align="center"
label="开始时间"
prop="createTime"
min-width="140"
/>
<el-table-column
:formatter="dateFormatter"
align="center"
label="结束时间"
prop="endTime"
min-width="140"
/>
<el-table-column align="center" label="审批状态" prop="status" min-width="90">
<template #default="scope">
<dict-tag :type="DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column align="center" label="耗时" prop="durationInMillis" width="100">
<template #default="scope">
{{ formatPast2(scope.row.durationInMillis) }}
</template>
</el-table-column>
</el-table>
</el-row>
</el-dialog>
</template>
<script setup lang="ts">
import { SimpleFlowNode } from '../consts'
@ -83,17 +87,17 @@ const dialogVisible = ref(false) // 弹窗可见性
const processInstanceInfos = ref<any[]>([]) //
const nodeClick = () => {
if (readonly) {
if(processInstance && processInstance.value){
if (readonly) {
if (processInstance && processInstance.value) {
processInstanceInfos.value = [
{
assigneeUser: processInstance.value.startUser,
createTime: processInstance.value.startTime,
endTime: processInstance.value.endTime,
status: processInstance.value.status,
durationInMillis: processInstance.value.durationInMillis
}
]
{
assigneeUser: processInstance.value.startUser,
createTime: processInstance.value.startTime,
endTime: processInstance.value.endTime,
status: processInstance.value.status,
durationInMillis: processInstance.value.durationInMillis
}
]
dialogVisible.value = true
}
}

View File

@ -8,9 +8,9 @@
>
<span class="iconfont icon-exclusive icon-size condition"></span>
</div>
<el-button v-else class="branch-node-add" color="#67c23a" @click="addCondition" plain
>添加条件</el-button
>
<el-button v-else class="branch-node-add" color="#67c23a" @click="addCondition" plain>
添加条件
</el-button>
<div
class="branch-node-item"

View File

@ -8,9 +8,9 @@
>
<span class="iconfont icon-inclusive icon-size inclusive"></span>
</div>
<el-button v-else class="branch-node-add" color="#345da2" @click="addCondition" plain
>添加条件</el-button
>
<el-button v-else class="branch-node-add" color="#345da2" @click="addCondition" plain>
添加条件
</el-button>
<div
class="branch-node-item"
v-for="(item, index) in currentNode.conditionNodes"

View File

@ -8,9 +8,9 @@
>
<span class="iconfont icon-parallel icon-size parallel"></span>
</div>
<el-button v-else class="branch-node-add" color="#626aef" @click="addCondition" plain
>添加分支</el-button
>
<el-button v-else class="branch-node-add" color="#626aef" @click="addCondition" plain>
添加分支
</el-button>
<div
class="branch-node-item"
v-for="(item, index) in currentNode.conditionNodes"

View File

@ -35,9 +35,9 @@
<Icon v-if="!readonly" icon="ep:arrow-right-bold" />
</div>
<div v-if="!readonly" class="node-toolbar">
<div class="toolbar-icon"
><Icon color="#0089ff" icon="ep:circle-close-filled" :size="18" @click="deleteNode"
/></div>
<div class="toolbar-icon">
<Icon color="#0089ff" icon="ep:circle-close-filled" :size="18" @click="deleteNode" />
</div>
</div>
</div>

View File

@ -9,9 +9,9 @@
]"
>
<div class="node-title-container">
<div class="node-title-icon start-user"
><span class="iconfont icon-start-user"></span
></div>
<div class="node-title-icon start-user">
<span class="iconfont icon-start-user"></span>
</div>
<input
v-if="!readonly && showInput"
type="text"

View File

@ -35,9 +35,9 @@
<Icon v-if="!readonly" icon="ep:arrow-right-bold" />
</div>
<div v-if="!readonly" class="node-toolbar">
<div class="toolbar-icon"
><Icon color="#0089ff" icon="ep:circle-close-filled" :size="18" @click="deleteNode"
/></div>
<div class="toolbar-icon">
<Icon color="#0089ff" icon="ep:circle-close-filled" :size="18" @click="deleteNode" />
</div>
</div>
</div>

View File

@ -40,9 +40,9 @@
<Icon icon="ep:arrow-right-bold" v-if="!readonly" />
</div>
<div v-if="!readonly" class="node-toolbar">
<div class="toolbar-icon"
><Icon color="#0089ff" icon="ep:circle-close-filled" :size="18" @click="deleteNode"
/></div>
<div class="toolbar-icon">
<Icon color="#0089ff" icon="ep:circle-close-filled" :size="18" @click="deleteNode" />
</div>
</div>
</div>
<!-- 传递子节点给添加节点组件会在子节点前面添加节点 -->

View File

@ -9,7 +9,6 @@ import { set } from 'lodash-es'
import { Pagination, TableColumn, TableSetPropsType, TableSlotDefault } from '@/types/table'
export default defineComponent({
// eslint-disable-next-line vue/no-reserved-component-names
name: 'Table',
props: {
pageSize: propTypes.number.def(10),

View File

@ -33,8 +33,8 @@ import { ElTable } from 'element-plus'
defineOptions({ name: 'TableSelectForm' })
withDefaults(
defineProps<{
modelValue: any[]
title: string
modelValue?: any[]
title?: string
}>(),
{ modelValue: () => [], title: '选择' }
)

View File

@ -1,5 +1,5 @@
<template>
<div class="upload-box">
<div class="upload-box" :style="uploadStyle">
<el-upload
:id="uuid"
:accept="fileType.join(',')"
@ -82,6 +82,13 @@ const props = defineProps({
showBtnText: propTypes.bool.def(true), //
directory: propTypes.string.def(undefined) // ==> undefined
})
const uploadStyle = computed(() => ({
'--upload-width': props.width,
'--upload-height': props.height,
'--upload-border-radius': props.borderradius
}))
const { t } = useI18n() //
const message = useMessage() //
// id
@ -167,11 +174,11 @@ const uploadError = () => {
display: flex;
align-items: center;
justify-content: center;
width: v-bind(width);
height: v-bind(height);
width: var(--upload-width);
height: var(--upload-height);
overflow: hidden;
border: 1px dashed var(--el-border-color-darker);
border-radius: v-bind(borderradius);
border-radius: var(--upload-border-radius);
transition: var(--el-transition-duration-fast);
&:hover {
@ -192,7 +199,7 @@ const uploadError = () => {
overflow: hidden;
background-color: transparent;
border: 1px dashed var(--el-border-color-darker);
border-radius: v-bind(borderradius);
border-radius: var(--upload-border-radius);
&:hover {
border: 1px dashed var(--el-color-primary);

View File

@ -1,5 +1,5 @@
<template>
<div class="upload-box">
<div class="upload-box" :style="uploadStyle">
<el-upload
v-model:file-list="fileList"
:accept="fileType.join(',')"
@ -85,6 +85,12 @@ const props = defineProps({
directory: propTypes.string.def(undefined) // ==> undefined
})
const uploadStyle = computed(() => ({
'--upload-width': props.width,
'--upload-height': props.height,
'--upload-border-radius': props.borderradius
}))
const { uploadUrl, httpRequest } = useUpload(props.directory)
const fileList = ref<UploadUserFile[]>([])
@ -238,7 +244,7 @@ const handleExceed = () => {
padding: 0;
overflow: hidden;
border: 1px dashed var(--el-border-color-darker);
border-radius: v-bind(borderradius);
border-radius: var(--upload-border-radius);
&:hover {
border: 1px dashed var(--el-color-primary);
@ -252,10 +258,10 @@ const handleExceed = () => {
.el-upload-list__item,
.el-upload--picture-card {
width: v-bind(width);
height: v-bind(height);
width: var(--upload-width);
height: var(--upload-height);
background-color: transparent;
border-radius: v-bind(borderradius);
border-radius: var(--upload-border-radius);
}
.upload-image {

View File

@ -158,11 +158,13 @@ defineExpose({ open }) // 提供 open 方法,用于打开弹窗
.el-transfer {
display: flex;
}
.el-transfer__buttons {
display: flex !important;
flex-direction: column-reverse;
justify-content: center;
gap: 20px;
.el-transfer__button:nth-child(2) {
margin: 0;
}

View File

@ -176,6 +176,41 @@ const processReZoom = () => {
bpmnViewer.value?.get('canvas').zoom('fit-viewport', 'auto')
}
let resizeObserver: ResizeObserver | null = null
/** 停止 ResizeObserver */
const stopResizeObserver = () => {
if (resizeObserver) {
resizeObserver.disconnect()
resizeObserver = null
}
}
/** 启动 ResizeObserver 监听容器尺寸变化 */
const startResizeObserver = () => {
stopResizeObserver()
if (!processCanvas.value || !bpmnViewer.value) {
return
}
const { clientWidth, clientHeight } = processCanvas.value
if (clientWidth > 0 && clientHeight > 0) {
processReZoom()
return
}
resizeObserver = new ResizeObserver((entries) => {
for (const entry of entries) {
const { width, height } = entry.contentRect
if (width > 0 && height > 0 && bpmnViewer.value) {
processReZoom()
stopResizeObserver()
}
}
})
resizeObserver.observe(processCanvas.value)
}
/** Zoom放大 */
const processZoomIn = (zoomStep = 0.1) => {
let newZoom = Math.floor(defaultZoom.value * 100 + zoomStep * 100) / 100
@ -198,6 +233,7 @@ const processZoomOut = (zoomStep = 0.1) => {
/** 流程图预览清空 */
const clearViewer = () => {
stopResizeObserver()
if (processCanvas.value) {
processCanvas.value.innerHTML = ''
}
@ -277,6 +313,12 @@ const importXML = async (xml: string) => {
isLoading.value = false
//
setProcessStatus(props.view)
// ResizeObserver
// https://github.com/yudaocode/yudao-ui-admin-vue3/pull/221
if (bpmnViewer.value) {
await nextTick()
startResizeObserver()
}
}
}
}

View File

@ -12,7 +12,6 @@ import { isFunction, isObject, some } from 'min-dash'
const WILDCARD = '*'
function CamundaModdleExtension(eventBus) {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const self = this
eventBus.on('moddleCopy.canCopyProperty', function (context) {

View File

@ -27,9 +27,9 @@
<element-form :id="elementId" :type="elementType" />
</el-collapse-item>
<el-collapse-item name="task" v-if="isTaskCollapseItemShow(elementType)" key="task">
<template #title
><Icon icon="ep:checked" />{{ getTaskCollapseItemName(elementType) }}</template
>
<template #title>
<Icon icon="ep:checked" />{{ getTaskCollapseItemName(elementType) }}
</template>
<element-task :id="elementId" :type="elementType" />
</el-collapse-item>
<el-collapse-item

View File

@ -112,9 +112,9 @@
:placeholder="item.displayName"
v-if="btnDisplayNameEdit[index]"
/>
<el-button v-else text @click="changeBtnDisplayName(index)"
>{{ item.displayName }} &nbsp;<Icon icon="ep:edit"
/></el-button>
<el-button v-else text @click="changeBtnDisplayName(index)">
{{ item.displayName }} &nbsp;<Icon icon="ep:edit" />
</el-button>
</div>
<div class="button-setting-item-label">
<el-switch v-model="item.enable" @change="updateElementExtensions" />
@ -127,15 +127,15 @@
<div class="field-permit-title">
<div class="setting-title-label first-title"> 字段名称 </div>
<div class="other-titles">
<span class="setting-title-label cursor-pointer" @click="updatePermission('READ')"
>只读</span
>
<span class="setting-title-label cursor-pointer" @click="updatePermission('WRITE')"
>可编辑</span
>
<span class="setting-title-label cursor-pointer" @click="updatePermission('NONE')"
>隐藏</span
>
<span class="setting-title-label cursor-pointer" @click="updatePermission('READ')">
只读
</span>
<span class="setting-title-label cursor-pointer" @click="updatePermission('WRITE')">
可编辑
</span>
<span class="setting-title-label cursor-pointer" @click="updatePermission('NONE')">
隐藏
</span>
</div>
</div>
<div class="field-setting-item" v-for="(item, index) in fieldsPermissionEl" :key="index">

View File

@ -11,13 +11,13 @@
/>
<el-table-column label="操作" width="100px">
<template #default="scope">
<el-button size="small" link @click="openListenerForm(scope.row, scope.$index)"
>编辑</el-button
>
<el-button size="small" link @click="openListenerForm(scope.row, scope.$index)">
编辑
</el-button>
<el-divider direction="vertical" />
<el-button size="small" link style="color: #ff4d4f" @click="removeListener(scope.$index)"
>移除</el-button
>
<el-button size="small" link style="color: #ff4d4f" @click="removeListener(scope.$index)">
移除
</el-button>
</template>
</el-table-column>
</el-table>
@ -167,17 +167,18 @@
/>
<el-table-column label="操作" width="130px">
<template #default="scope">
<el-button size="small" link @click="openListenerFieldForm(scope.row, scope.$index)"
>编辑</el-button
>
<el-button size="small" link @click="openListenerFieldForm(scope.row, scope.$index)">
编辑
</el-button>
<el-divider direction="vertical" />
<el-button
size="small"
link
style="color: #ff4d4f"
@click="removeListenerField(scope.$index)"
>移除</el-button
>
移除
</el-button>
</template>
</el-table-column>
</el-table>
@ -419,10 +420,7 @@ const saveListenerConfig = async () => {
bpmnElement.businessObject?.extensionElements?.values?.filter(
(ex) => ex.$type !== `${prefix}:ExecutionListener`
) ?? []
updateElementExtensions(
bpmnElement,
otherExtensionList.value.concat(bpmnElementListeners.value)
)
updateElementExtensions(bpmnElement, otherExtensionList.value.concat(bpmnElementListeners.value))
// 4.
listenerFormModelVisible.value = false
listenerForm.value = {}
@ -448,10 +446,7 @@ const selectProcessListener = (listener) => {
bpmnElement.businessObject?.extensionElements?.values?.filter(
(ex) => ex.$type !== `${prefix}:ExecutionListener`
) ?? []
updateElementExtensions(
bpmnElement,
otherExtensionList.value.concat(bpmnElementListeners.value)
)
updateElementExtensions(bpmnElement, otherExtensionList.value.concat(bpmnElementListeners.value))
}
watch(

View File

@ -17,17 +17,18 @@
/>
<el-table-column label="操作" width="90px">
<template #default="scope">
<el-button size="small" link @click="openListenerForm(scope.row, scope.$index)"
>编辑</el-button
>
<el-button size="small" link @click="openListenerForm(scope.row, scope.$index)">
编辑
</el-button>
<el-divider direction="vertical" />
<el-button
size="small"
link
style="color: #ff4d4f"
@click="removeListener(scope.row, scope.$index)"
>移除</el-button
>
移除
</el-button>
</template>
</el-table-column>
</el-table>
@ -183,9 +184,9 @@
<el-divider />
<p class="listener-filed__title">
<span><Icon icon="ep:menu" />注入字段</span>
<el-button size="small" type="primary" @click="openListenerFieldForm(null)"
>添加字段</el-button
>
<el-button size="small" type="primary" @click="openListenerFieldForm(null)">
添加字段
</el-button>
</p>
<el-table
:data="fieldsListOfListener"
@ -211,17 +212,18 @@
/>
<el-table-column label="操作" width="100px">
<template #default="scope">
<el-button size="small" link @click="openListenerFieldForm(scope.row, scope.$index)"
>编辑</el-button
>
<el-button size="small" link @click="openListenerFieldForm(scope.row, scope.$index)">
编辑
</el-button>
<el-divider direction="vertical" />
<el-button
size="small"
link
style="color: #ff4d4f"
@click="removeListenerField(scope.row, scope.$index)"
>移除</el-button
>
移除
</el-button>
</template>
</el-table-column>
</el-table>
@ -423,10 +425,7 @@ const saveListenerConfig = async () => {
bpmnElement.businessObject?.extensionElements?.values?.filter(
(ex) => ex.$type !== `${prefix}:TaskListener`
) ?? []
updateElementExtensions(
bpmnElement,
otherExtensionList.value.concat(bpmnElementListeners.value)
)
updateElementExtensions(bpmnElement, otherExtensionList.value.concat(bpmnElementListeners.value))
// 4.
listenerFormModelVisible.value = false
listenerForm.value = {}
@ -490,10 +489,7 @@ const selectProcessListener = (listener) => {
bpmnElement.businessObject?.extensionElements?.values?.filter(
(ex) => ex.$type !== `${prefix}:TaskListener`
) ?? []
updateElementExtensions(
bpmnElement,
otherExtensionList.value.concat(bpmnElementListeners.value)
)
updateElementExtensions(bpmnElement, otherExtensionList.value.concat(bpmnElementListeners.value))
}
watch(

View File

@ -27,9 +27,7 @@
</div>
</div>
</el-radio-group>
<div v-else>
除了UserTask以外节点的多实例待实现
</div>
<div v-else> UserTask </div>
<!-- 与Simple设计器配置合并保留以前的代码 -->
<el-form label-width="90px" style="display: none">
<el-form-item label="快捷配置">

View File

@ -141,8 +141,8 @@ watch(
.header-editor {
.header-list {
max-height: 400px;
overflow-y: auto;
margin-bottom: 16px;
overflow-y: auto;
}
.header-item {
@ -156,8 +156,8 @@ watch(
}
.separator {
color: #606266;
font-weight: 500;
color: #606266;
}
.header-value {

View File

@ -23,8 +23,8 @@
<div style="margin-bottom: 8px">
<el-radio-group v-model="cronMode[f.key]" :key="'radio-' + f.key">
<el-radio label="every" :key="'every-' + f.key">{{ f.label }}</el-radio>
<el-radio label="range" :key="'range-' + f.key"
>
<el-radio label="range" :key="'range-' + f.key">
<el-input-number
v-model="cronRange[f.key][0]"
:min="f.min"
@ -42,10 +42,10 @@
style="width: 60px"
:key="'range1-' + f.key"
/>
之间每{{ f.label }}</el-radio
>
<el-radio label="step" :key="'step-' + f.key"
>从第
之间每{{ f.label }}
</el-radio>
<el-radio label="step" :key="'step-' + f.key">
从第
<el-input-number
v-model="cronStep[f.key][0]"
:min="f.min"
@ -63,8 +63,8 @@
style="width: 60px"
:key="'step1-' + f.key"
/>
{{ f.label }}</el-radio
>
{{ f.label }}
</el-radio>
<el-radio label="appoint" :key="'appoint-' + f.key">指定</el-radio>
</el-radio-group>
</div>
@ -74,8 +74,9 @@
v-for="n in f.max + 1"
:label="pad(n - 1)"
:key="'cb-' + f.key + '-' + (n - 1)"
>{{ pad(n - 1) }}</el-checkbox
>
{{ pad(n - 1) }}
</el-checkbox>
</el-checkbox-group>
</div>
</el-tab-pane>
@ -90,73 +91,79 @@
:key="'isoStr'"
/>
</div>
<div style="margin-bottom: 10px"
>循环次数<el-input-number v-model="repeat" :min="1" style="width: 100px" :key="'repeat'"
/></div>
<div style="margin-bottom: 10px"
>日期时间<el-date-picker
<div style="margin-bottom: 10px">
循环次数<el-input-number v-model="repeat" :min="1" style="width: 100px" :key="'repeat'" />
</div>
<div style="margin-bottom: 10px">
日期时间<el-date-picker
v-model="isoDate"
type="datetime"
placeholder="选择日期时间"
style="width: 200px"
:key="'isoDate'"
/></div>
<div style="margin-bottom: 10px"
>当前时长<el-input
/>
</div>
<div style="margin-bottom: 10px">
当前时长<el-input
v-model="isoDuration"
placeholder="如P3DT30M30S"
style="width: 200px"
:key="'isoDuration'"
/></div>
/>
</div>
<div>
<div
><el-button
<div>
<el-button
v-for="s in [5, 10, 30, 50]"
@click="setDuration('S', s)"
:key="'sec-' + s"
>{{ s }}</el-button
>自定义</div
>
<div
><el-button
>
{{ s }}
</el-button>
自定义
</div>
<div>
<el-button
v-for="m in [5, 10, 30, 50]"
@click="setDuration('M', m)"
:key="'min-' + m"
>{{ m }}</el-button
>自定义</div
>
<div
>小时<el-button
>
{{ m }}
</el-button>
自定义
</div>
<div>
小时<el-button
v-for="h in [4, 8, 12, 24]"
@click="setDuration('H', h)"
:key="'hour-' + h"
>{{ h }}</el-button
>自定义</div
>
<div
><el-button
v-for="d in [1, 2, 3, 4]"
@click="setDuration('D', d)"
:key="'day-' + d"
>{{ d }}</el-button
>自定义</div
>
<div
><el-button
>
{{ h }}
</el-button>
自定义
</div>
<div>
<el-button v-for="d in [1, 2, 3, 4]" @click="setDuration('D', d)" :key="'day-' + d">
{{ d }}
</el-button>
自定义
</div>
<div>
<el-button
v-for="mo in [1, 2, 3, 4]"
@click="setDuration('M', mo)"
:key="'mon-' + mo"
>{{ mo }}</el-button
>自定义</div
>
<div
><el-button
v-for="y in [1, 2, 3, 4]"
@click="setDuration('Y', y)"
:key="'year-' + y"
>{{ y }}</el-button
>自定义</div
>
>
{{ mo }}
</el-button>
自定义
</div>
<div>
<el-button v-for="y in [1, 2, 3, 4]" @click="setDuration('Y', y)" :key="'year-' + y">
{{ y }}
</el-button>
自定义
</div>
</div>
</el-tab-pane>
</el-tabs>

View File

@ -1,8 +1,8 @@
<template>
<div>
<div style="margin-bottom: 10px"
>当前选择<el-input v-model="isoString" readonly style="width: 300px"
/></div>
<div style="margin-bottom: 10px">
当前选择<el-input v-model="isoString" readonly style="width: 300px" />
</div>
<div v-for="unit in units" :key="unit.key" style="margin-bottom: 8px">
<span>{{ unit.label }}</span>
<el-button-group>
@ -11,8 +11,9 @@
:key="val"
size="mini"
@click="setUnit(unit.key, val)"
>{{ val }}</el-button
>
{{ val }}
</el-button>
<el-input
v-model.number="custom[unit.key]"
size="mini"

View File

@ -3,22 +3,23 @@
<div style="margin-top: 10px">
<span>类型</span>
<el-button-group>
<el-button size="mini" :type="type === 'time' ? 'primary' : ''" @click="setType('time')"
>时间</el-button
>
<el-button size="mini" :type="type === 'time' ? 'primary' : ''" @click="setType('time')">
时间
</el-button>
<el-button
size="mini"
:type="type === 'duration' ? 'primary' : ''"
@click="setType('duration')"
>持续</el-button
>
<el-button size="mini" :type="type === 'cycle' ? 'primary' : ''" @click="setType('cycle')"
>循环</el-button
>
持续
</el-button>
<el-button size="mini" :type="type === 'cycle' ? 'primary' : ''" @click="setType('cycle')">
循环
</el-button>
</el-button-group>
<el-icon v-if="valid" color="green" style="margin-left: 8px"><CircleCheckFilled /></el-icon>
</div>
<div style="margin-top: 10px; display: flex; align-items: center">
<div style="display: flex; margin-top: 10px; align-items: center">
<span>条件</span>
<el-input
v-model="condition"
@ -33,9 +34,9 @@
<el-icon color="orange"><WarningFilled /></el-icon>
</el-tooltip>
<el-tooltip :content="helpText" placement="top">
<el-icon color="#409EFF" style="cursor: pointer" @click="showHelp = true"
><QuestionFilled
/></el-icon>
<el-icon color="#409EFF" style="cursor: pointer" @click="showHelp = true">
<QuestionFilled />
</el-icon>
</el-tooltip>
<el-button
v-if="type === 'time'"

View File

@ -13,8 +13,8 @@
</div>
</div>
<div class="flex flex-col justify-between">
<div :class="`${prefixCls}__item--text text-16px text-gray-500 text-right`"
>{{ t('analysis.newUser') }}
<div :class="`${prefixCls}__item--text text-16px text-gray-500 text-right`">
{{ t('analysis.newUser') }}
</div>
<CountTo
:duration="2600"
@ -42,8 +42,8 @@
</div>
</div>
<div class="flex flex-col justify-between">
<div :class="`${prefixCls}__item--text text-16px text-gray-500 text-right`"
>{{ t('analysis.unreadInformation') }}
<div :class="`${prefixCls}__item--text text-16px text-gray-500 text-right`">
{{ t('analysis.unreadInformation') }}
</div>
<CountTo
:duration="2600"
@ -71,8 +71,8 @@
</div>
</div>
<div class="flex flex-col justify-between">
<div :class="`${prefixCls}__item--text text-16px text-gray-500 text-right`"
>{{ t('analysis.transactionAmount') }}
<div :class="`${prefixCls}__item--text text-16px text-gray-500 text-right`">
{{ t('analysis.transactionAmount') }}
</div>
<CountTo
:duration="2600"
@ -100,8 +100,8 @@
</div>
</div>
<div class="flex flex-col justify-between">
<div :class="`${prefixCls}__item--text text-16px text-gray-500 text-right`"
>{{ t('analysis.totalShopping') }}
<div :class="`${prefixCls}__item--text text-16px text-gray-500 text-right`">
{{ t('analysis.totalShopping') }}
</div>
<CountTo
:duration="2600"

View File

@ -33,11 +33,11 @@
<!-- 右上角的主题语言选择 -->
<div
class="flex items-center justify-between at-2xl:justify-end at-xl:justify-end"
style="color: var(--el-text-color-primary);"
style="color: var(--el-text-color-primary)"
>
<div class="flex items-center at-2xl:hidden at-xl:hidden">
<img alt="" class="mr-10px h-48px w-48px" src="@/assets/imgs/logo.png" />
<span class="text-20px font-bold" >{{ underlineToHump(appStore.getTitle) }}</span>
<span class="text-20px font-bold">{{ underlineToHump(appStore.getTitle) }}</span>
</div>
<div class="flex items-center justify-end space-x-10px h-48px">
<ThemeSwitch />
@ -75,7 +75,14 @@ import { useAppStore } from '@/store/modules/app'
import { ThemeSwitch } from '@/layout/components/ThemeSwitch'
import { LocaleDropdown } from '@/layout/components/LocaleDropdown'
import { LoginForm, MobileForm, QrCodeForm, RegisterForm, SSOLoginVue, ForgetPasswordForm } from './components'
import {
LoginForm,
MobileForm,
QrCodeForm,
RegisterForm,
SSOLoginVue,
ForgetPasswordForm
} from './components'
defineOptions({ name: 'Login' })

View File

@ -114,8 +114,8 @@
</el-checkbox>
</el-col>
<el-col :offset="6" :span="12">
<el-link style="float: right" type="primary"
>{{ t('login.forgetPassword') }}
<el-link style="float: right" type="primary">
{{ t('login.forgetPassword') }}
</el-link>
</el-col>
</el-row>

View File

@ -60,12 +60,12 @@
class="py-0.5 px-2.5"
style="
max-width: 220px;
overflow: hidden;
font-size: 14px;
font-weight: 400;
color: var(--el-text-color-regular);
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
white-space: nowrap;
"
>
{{ conversation.title }}
@ -103,9 +103,9 @@
<div
class="absolute bottom-0 left-0 right-0 px-5 leading-8.75 flex justify-between items-center"
style="
color: var(--el-text-color);
background-color: var(--el-fill-color-extra-light);
box-shadow: 0 0 1px 1px var(--el-border-color-lighter);
color: var(--el-text-color);
"
>
<div

View File

@ -53,11 +53,12 @@
<Icon :icon="getFileIcon(file.name)" class="text-blue-500 mr-2 flex-shrink-0" />
<span
class="font-medium text-gray-900 mr-1 overflow-hidden text-ellipsis whitespace-nowrap flex-1"
>{{ file.name }}</span
>
<span class="text-gray-500 flex-shrink-0 text-11px"
>({{ formatFileSize(file.size) }})</span
>
{{ file.name }}
</span>
<span class="text-gray-500 flex-shrink-0 text-11px">
({{ formatFileSize(file.size) }})
</span>
</div>
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
<el-progress
@ -286,27 +287,29 @@ onUnmounted(() => {
--el-button-border-color: transparent;
--el-button-hover-bg-color: var(--el-fill-color-light);
--el-button-hover-border-color: transparent;
color: var(--el-text-color-regular);
}
.upload-btn.has-files {
color: var(--el-color-primary);
--el-button-hover-bg-color: var(--el-color-primary-light-9);
color: var(--el-color-primary);
}
.file-tooltip {
position: absolute;
bottom: calc(100% + 8px);
left: 50%;
transform: translateX(-50%);
z-index: 1000;
max-width: 320px;
min-width: 240px;
padding: 8px;
background: white;
border: 1px solid var(--el-border-color-light);
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
z-index: 1000;
min-width: 240px;
max-width: 320px;
padding: 8px;
transform: translateX(-50%);
box-shadow: 0 4px 12px rgb(0 0 0 / 15%);
animation: fadeInDown 0.2s ease;
}
@ -314,25 +317,25 @@ onUnmounted(() => {
position: absolute;
bottom: -5px;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 5px solid var(--el-border-color-light);
border-right: 5px solid transparent;
border-left: 5px solid transparent;
transform: translateX(-50%);
}
/* Tooltip 箭头伪元素 */
.tooltip-arrow::after {
content: '';
position: absolute;
bottom: 1px;
left: -4px;
width: 0;
height: 0;
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: 4px solid white;
border-right: 4px solid transparent;
border-left: 4px solid transparent;
content: '';
}
@keyframes fadeInDown {
@ -340,6 +343,7 @@ onUnmounted(() => {
opacity: 0;
transform: translateX(-50%) translateY(4px);
}
to {
opacity: 1;
transform: translateX(-50%) translateY(0);
@ -351,6 +355,7 @@ onUnmounted(() => {
opacity: 0;
transform: translateX(-50%) translateY(4px);
}
to {
opacity: 1;
transform: translateX(-50%) translateY(0);
@ -374,6 +379,7 @@ onUnmounted(() => {
.file-list::-webkit-scrollbar-thumb:hover {
background: var(--el-border-color);
}
/* 滚动条样式 */
.file-list::-webkit-scrollbar {
width: 4px;

View File

@ -79,11 +79,11 @@ const toggleExpanded = () => {
}
.max-h-300px::-webkit-scrollbar-thumb {
background: rgba(156, 163, 175, 0.4);
background: rgb(156 163 175 / 40%);
border-radius: 2px;
}
.max-h-300px::-webkit-scrollbar-thumb:hover {
background: rgba(156, 163, 175, 0.6);
background: rgb(156 163 175 / 60%);
}
</style>

View File

@ -228,8 +228,8 @@ onMounted(async () => {
}
.el-tabs__header {
margin: 0 !important;
padding: 0 !important;
margin: 0 !important;
}
.el-tabs__nav-wrap {
@ -241,6 +241,6 @@ onMounted(async () => {
}
.el-tab-pane {
padding: 8px 0 0 0 !important;
padding: 8px 0 0 !important;
}
</style>

View File

@ -57,16 +57,16 @@
class="content-expand"
style="
padding: 10px 20px;
white-space: pre-wrap;
line-height: 1.5;
white-space: pre-wrap;
background-color: #f9f9f9;
border-radius: 4px;
border-left: 3px solid #409eff;
border-radius: 4px;
"
>
<div
class="content-title"
style="margin-bottom: 8px; color: #606266; font-size: 14px; font-weight: bold"
style="margin-bottom: 8px; font-size: 14px; font-weight: bold; color: #606266"
>
完整内容
</div>

View File

@ -143,11 +143,12 @@ defineExpose({
flex-direction: column;
:deep(.el-card__body) {
@extend .hide-scroll-bar;
padding: 0;
overflow-y: auto;
box-sizing: border-box;
flex-grow: 1;
overflow-y: auto;
padding: 0;
@extend .hide-scroll-bar;
}
}

View File

@ -1,9 +1,9 @@
<template>
<div class="flex h-full items-stretch">
<div class="flex h-full items-stretch">
<!-- 模式 -->
<Mode class="flex-none" @generate-music="generateMusic"/>
<Mode class="flex-none" @generate-music="generateMusic" />
<!-- 音频列表 -->
<List ref="listRef" class="flex-auto"/>
<List ref="listRef" class="flex-auto" />
</div>
</template>
@ -13,14 +13,14 @@ import List from './list/index.vue'
defineOptions({ name: 'Index' })
const listRef = ref<Nullable<{generateMusic: (...args) => void}>>(null)
const listRef = ref<Nullable<{ generateMusic: (...args) => void }>>(null)
/*
*@Description: 拿到左侧配置信息调用右侧音乐生成的方法
*@MethodAuthor: xiaohong
*@Date: 2024-07-19 11:13:38
*/
function generateMusic (args: {formData: Recordable}) {
unref(listRef)?.generateMusic(args.formData)
*/
function generateMusic(args: { formData: Recordable }) {
unref(listRef)?.generateMusic(args.formData)
}
</script>

View File

@ -1,34 +1,55 @@
<template>
<div class="flex items-center justify-between px-2 h-72px bg-[var(--el-bg-color-overlay)] b-solid b-1 b-[var(--el-border-color)] b-l-none">
<div
class="flex items-center justify-between px-2 h-72px bg-[var(--el-bg-color-overlay)] b-solid b-1 b-[var(--el-border-color)] b-l-none"
>
<!-- 歌曲信息 -->
<div class="flex gap-[10px]">
<el-image src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" class="w-[45px]"/>
<el-image
src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
class="w-[45px]"
/>
<div>
<div>{{currentSong.name}}</div>
<div class="text-[12px] text-gray-400">{{currentSong.singer}}</div>
<div>{{ currentSong.name }}</div>
<div class="text-[12px] text-gray-400">{{ currentSong.singer }}</div>
</div>
</div>
<!-- 音频controls -->
<div class="flex gap-[12px] items-center">
<Icon icon="majesticons:back-circle" :size="20" class="text-gray-300 cursor-pointer"/>
<Icon :icon="audioProps.paused ? 'mdi:arrow-right-drop-circle' : 'solar:pause-circle-bold'" :size="30" class=" cursor-pointer" @click="toggleStatus('paused')"/>
<Icon icon="majesticons:next-circle" :size="20" class="text-gray-300 cursor-pointer"/>
<Icon icon="majesticons:back-circle" :size="20" class="text-gray-300 cursor-pointer" />
<Icon
:icon="audioProps.paused ? 'mdi:arrow-right-drop-circle' : 'solar:pause-circle-bold'"
:size="30"
class="cursor-pointer"
@click="toggleStatus('paused')"
/>
<Icon icon="majesticons:next-circle" :size="20" class="text-gray-300 cursor-pointer" />
<div class="flex gap-[16px] items-center">
<span>{{audioProps.currentTime}}</span>
<el-slider v-model="audioProps.duration" color="#409eff" class="w-[160px!important] "/>
<span>{{ audioProps.currentTime }}</span>
<el-slider v-model="audioProps.duration" color="#409eff" class="w-[160px!important]" />
<span>{{ audioProps.duration }}</span>
</div>
<!-- 音频 -->
<audio v-bind="audioProps" ref="audioRef" controls v-show="!audioProps" @timeupdate="audioTimeUpdate">
<source :src="audioUrl"/>
<audio
v-bind="audioProps"
ref="audioRef"
controls
v-show="!audioProps"
@timeupdate="audioTimeUpdate"
>
<source :src="audioUrl" />
</audio>
</div>
<!-- 音量控制器 -->
<div class="flex gap-[16px] items-center">
<Icon :icon="audioProps.muted ? 'tabler:volume-off' : 'tabler:volume'" :size="20" class="cursor-pointer" @click="toggleStatus('muted')"/>
<el-slider v-model="audioProps.volume" color="#409eff" class="w-[160px!important] "/>
<Icon
:icon="audioProps.muted ? 'tabler:volume-off' : 'tabler:volume'"
:size="20"
class="cursor-pointer"
@click="toggleStatus('muted')"
/>
<el-slider v-model="audioProps.volume" color="#409eff" class="w-[160px!important]" />
</div>
</div>
</template>
@ -42,17 +63,17 @@ defineOptions({ name: 'Index' })
const currentSong = inject('currentSong', {})
const audioRef = ref<Nullable<HTMLElement>>(null)
// https://www.runoob.com/tags/ref-av-dom.html
// https://www.runoob.com/tags/ref-av-dom.html
const audioProps = reactive({
autoplay: true,
paused: false,
currentTime: '00:00',
duration: '00:00',
muted: false,
volume: 50,
muted: false,
volume: 50
})
function toggleStatus (type: string) {
function toggleStatus(type: string) {
audioProps[type] = !audioProps[type]
if (type === 'paused' && audioRef.value) {
if (audioProps[type]) {
@ -64,7 +85,7 @@ function toggleStatus (type: string) {
}
//
function audioTimeUpdate (args) {
function audioTimeUpdate(args) {
audioProps.currentTime = formatPast(new Date(args.timeStamp), 'mm:ss')
}
</script>

View File

@ -6,26 +6,26 @@
<el-tab-pane v-loading="loading" label="我的创作" name="mine">
<el-row v-if="mySongList.length" :gutter="12">
<el-col v-for="song in mySongList" :key="song.id" :span="24">
<songCard :songInfo="song" @play="setCurrentSong(song)"/>
<songCard :songInfo="song" @play="setCurrentSong(song)" />
</el-col>
</el-row>
<el-empty v-else description="暂无音乐"/>
<el-empty v-else description="暂无音乐" />
</el-tab-pane>
<!-- 试听广场 -->
<el-tab-pane v-loading="loading" label="试听广场" name="square">
<el-row v-if="squareSongList.length" v-loading="loading" :gutter="12">
<el-col v-for="song in squareSongList" :key="song.id" :span="24">
<songCard :songInfo="song" @play="setCurrentSong(song)"/>
<songCard :songInfo="song" @play="setCurrentSong(song)" />
</el-col>
</el-row>
<el-empty v-else description="暂无音乐"/>
<el-empty v-else description="暂无音乐" />
</el-tab-pane>
</el-tabs>
<!-- songInfo -->
<songInfo class="flex-none"/>
<songInfo class="flex-none" />
</div>
<audioBar class="flex-none"/>
<audioBar class="flex-none" />
</div>
</template>
@ -36,7 +36,6 @@ import audioBar from './audioBar/index.vue'
defineOptions({ name: 'Index' })
const currentType = ref('mine')
// loading
const loading = ref(false)
@ -52,9 +51,9 @@ provide('currentSong', currentSong)
*@Description: 调接口生成音乐列表
*@MethodAuthor: xiaohong
*@Date: 2024-06-27 17:06:44
*/
function generateMusic (formData: Recordable) {
console.log(formData);
*/
function generateMusic(formData: Recordable) {
console.log(formData)
loading.value = true
setTimeout(() => {
mySongList.value = Array.from({ length: 20 }, (_, index) => {
@ -63,7 +62,8 @@ function generateMusic (formData: Recordable) {
audioUrl: '',
videoUrl: '',
title: '我走后' + index,
imageUrl: 'https://www.carsmp3.com/data/attachment/forum/201909/19/091020q5kgre20fidreqyt.jpg',
imageUrl:
'https://www.carsmp3.com/data/attachment/forum/201909/19/091020q5kgre20fidreqyt.jpg',
desc: 'Metal, symphony, film soundtrack, grand, majesticMetal, dtrack, grand, majestic',
date: '2024年04月30日 14:02:57',
lyric: `<div class="_words_17xen_66"><div>大江东去,浪淘尽,千古风流人物。
@ -85,8 +85,8 @@ function generateMusic (formData: Recordable) {
*@Description: 设置当前播放的音乐
*@MethodAuthor: xiaohong
*@Date: 2024-07-19 11:22:33
*/
function setCurrentSong (music: Recordable) {
*/
function setCurrentSong(music: Recordable) {
currentSong.value = music
}
@ -95,11 +95,11 @@ defineExpose({
})
</script>
<style lang="scss" scoped>
:deep(.el-tabs) {
display: flex;
flex-direction: column;
.el-tabs__content {
padding: 0 7px;
overflow: auto;

View File

@ -1,9 +1,18 @@
<template>
<div class="flex bg-[var(--el-bg-color-overlay)] p-12px mb-12px rounded-1">
<div class="relative" @click="playSong">
<el-image :src="songInfo.imageUrl" class="flex-none w-80px"/>
<div class="bg-black bg-op-40 absolute top-0 left-0 w-full h-full flex items-center justify-center cursor-pointer">
<Icon :icon="currentSong.id === songInfo.id ? 'solar:pause-circle-bold':'mdi:arrow-right-drop-circle'" :size="30" />
<el-image :src="songInfo.imageUrl" class="flex-none w-80px" />
<div
class="bg-black bg-op-40 absolute top-0 left-0 w-full h-full flex items-center justify-center cursor-pointer"
>
<Icon
:icon="
currentSong.id === songInfo.id
? 'solar:pause-circle-bold'
: 'mdi:arrow-right-drop-circle'
"
:size="30"
/>
</div>
</div>
<div class="ml-8px">
@ -16,7 +25,6 @@
</template>
<script lang="ts" setup>
defineOptions({ name: 'Index' })
defineProps({
@ -30,7 +38,7 @@ const emits = defineEmits(['play'])
const currentSong = inject('currentSong', {})
function playSong () {
function playSong() {
emits('play')
}
</script>

View File

@ -1,6 +1,6 @@
<template>
<ContentWrap class="w-300px mb-[0!important] line-height-24px">
<el-image :src="currentSong.imageUrl"/>
<el-image :src="currentSong.imageUrl" />
<div class="">{{ currentSong.title }}</div>
<div class="text-[var(--el-text-color-secondary)] text-12px line-clamp-1">
{{ currentSong.desc }}
@ -14,9 +14,7 @@
</template>
<script lang="ts" setup>
defineOptions({ name: 'Index' })
const currentSong = inject('currentSong', {})
</script>

View File

@ -1,9 +1,12 @@
<template>
<div>
<Title title="音乐/歌词说明" desc="描述您想要的音乐风格和主题,使用流派和氛围而不是特定的艺术家和歌曲">
<Title
title="音乐/歌词说明"
desc="描述您想要的音乐风格和主题,使用流派和氛围而不是特定的艺术家和歌曲"
>
<el-input
v-model="formData.desc"
:autosize="{ minRows: 6, maxRows: 6}"
:autosize="{ minRows: 6, maxRows: 6 }"
resize="none"
type="textarea"
maxlength="1200"
@ -14,20 +17,23 @@
<Title title="纯音乐" desc="创建一首没有歌词的歌曲">
<template #extra>
<el-switch v-model="formData.pure" size="small"/>
<el-switch v-model="formData.pure" size="small" />
</template>
</Title>
<Title title="版本" desc="描述您想要的音乐风格和主题,使用流派和氛围而不是特定的艺术家和歌曲">
<el-select v-model="formData.version" placeholder="请选择">
<el-option
v-for="item in [{
value: '3',
label: 'V3'
}, {
value: '2',
label: 'V2'
}]"
v-for="item in [
{
value: '3',
label: 'V3'
},
{
value: '2',
label: 'V2'
}
]"
:key="item.value"
:label="item.label"
:value="item.value"
@ -51,5 +57,4 @@ const formData = reactive({
defineExpose({
formData
})
</script>

View File

@ -3,7 +3,7 @@
<Title title="歌词" desc="自己编写歌词或使用Ai生成歌词两节/8行效果最佳">
<el-input
v-model="formData.lyric"
:autosize="{ minRows: 6, maxRows: 6}"
:autosize="{ minRows: 6, maxRows: 6 }"
resize="none"
type="textarea"
maxlength="1200"
@ -14,23 +14,28 @@
<Title title="音乐风格">
<el-space class="flex-wrap">
<el-tag v-for="tag in tags" :key="tag" round class="mb-8px">{{tag}}</el-tag>
<el-tag v-for="tag in tags" :key="tag" round class="mb-8px">{{ tag }}</el-tag>
</el-space>
<el-button
:type="showCustom ? 'primary': 'default'"
round
size="small"
:type="showCustom ? 'primary' : 'default'"
round
size="small"
class="mb-6px"
@click="showCustom = !showCustom"
>自定义风格
>
自定义风格
</el-button>
</Title>
<Title v-show="showCustom" desc="描述您想要的音乐风格Suno无法识别艺术家的名字但可以理解流派和氛围" class="-mt-12px">
<Title
v-show="showCustom"
desc="描述您想要的音乐风格Suno无法识别艺术家的名字但可以理解流派和氛围"
class="-mt-12px"
>
<el-input
v-model="formData.style"
:autosize="{ minRows: 4, maxRows: 4}"
:autosize="{ minRows: 4, maxRows: 4 }"
resize="none"
type="textarea"
maxlength="256"
@ -40,19 +45,22 @@
</Title>
<Title title="音乐/歌曲名称">
<el-input v-model="formData.name" placeholder="请输入音乐/歌曲名称"/>
<el-input v-model="formData.name" placeholder="请输入音乐/歌曲名称" />
</Title>
<Title title="版本">
<el-select v-model="formData.version" placeholder="请选择">
<el-option
v-for="item in [{
value: '3',
label: 'V3'
}, {
value: '2',
label: 'V2'
}]"
v-for="item in [
{
value: '3',
label: 'V3'
},
{
value: '2',
label: 'V2'
}
]"
:key="item.value"
:label="item.label"
:value="item.value"

View File

@ -1,11 +1,11 @@
<template>
<div class="mb-12px">
<div class="flex text-[var(--el-text-color-primary)] justify-between items-center">
<span>{{title}}</span>
<span>{{ title }}</span>
<slot name="extra"></slot>
</div>
<div class="text-[var(--el-text-color-secondary)] text-12px my-8px">
{{desc}}
{{ desc }}
</div>
<slot></slot>
</div>

View File

@ -47,8 +47,8 @@
<div v-else-if="error">
<el-text type="danger">{{ error }}</el-text>
</div>
<pre v-else-if="testResult" class="result-content"
>{{ JSON.stringify(testResult, null, 2) }}
<pre v-else-if="testResult" class="result-content">
{{ JSON.stringify(testResult, null, 2) }}
</pre>
<div v-else> <el-text type="info">点击运行查看结果</el-text> </div>
</div>
@ -237,14 +237,14 @@ defineExpose({
<style lang="css" scoped>
.result-content {
background: white;
padding: 12px;
border-radius: 4px;
max-height: 300px;
padding: 12px;
overflow: auto;
font-family: Monaco, Consolas, monospace;
font-size: 14px;
line-height: 1.5;
white-space: pre-wrap;
background: white;
border-radius: 4px;
}
</style>

View File

@ -110,11 +110,12 @@ watch(copied, (val) => {
flex-direction: column;
:deep(.el-card__body) {
@extend .hide-scroll-bar;
padding: 0;
overflow-y: auto;
box-sizing: border-box;
flex-grow: 1;
overflow-y: auto;
padding: 0;
@extend .hide-scroll-bar;
}
}
</style>

View File

@ -16,7 +16,7 @@
<script setup lang="ts">
const props = withDefaults(
defineProps<{
tags: { label: string; value: string }[]
tags?: { label: string; value: string }[]
modelValue: string
[k: string]: any
}>(),

View File

@ -90,9 +90,9 @@
<div class="flex flex-col">
<el-radio-group v-model="modelData.titleSetting.enable">
<div class="flex flex-col">
<el-radio :value="false"
>系统默认 <el-text type="info"> 展示流程名称 </el-text></el-radio
>
<el-radio :value="false">
系统默认 <el-text type="info"> 展示流程名称 </el-text>
</el-radio>
<el-radio :value="true">
自定义标题
<el-text>

View File

@ -82,9 +82,9 @@ onMounted(() => {
<style>
#mention-modal {
position: absolute;
border: 1px solid #ccc;
background-color: #fff;
padding: 5px;
background-color: #fff;
border: 1px solid #ccc;
}
#mention-modal input {
@ -98,10 +98,10 @@ onMounted(() => {
}
#mention-modal ul li {
list-style: none;
cursor: pointer;
padding: 3px 0;
text-align: left;
list-style: none;
cursor: pointer;
}
#mention-modal ul li:hover {

View File

@ -19,7 +19,6 @@ const view = ref({
bpmnXml: ''
}) // BPMN
/** 只有 loading 完成时,才去加载流程列表 */
watch(
() => props.modelView,
@ -42,8 +41,8 @@ watch(
</script>
<style lang="scss" scoped>
.box-card {
height: 100%;
width: 100%;
height: 100%;
margin-bottom: 0;
:deep(.el-card__body) {
@ -52,9 +51,9 @@ watch(
}
:deep(.process-viewer) {
width: 100%;
height: 100% !important;
min-height: 100%;
width: 100%;
overflow: auto;
}
}

View File

@ -95,16 +95,18 @@
</el-table-column>
<el-table-column label="字典类型" min-width="12%">
<template #default="scope">
<el-select v-model="scope.row.dictType" :value-on-clear="''" clearable filterable placeholder="请选择">
<el-select
v-model="scope.row.dictType"
:value-on-clear="''"
clearable
filterable
placeholder="请选择"
>
<template #header>
<div class="flex justify-end">
<el-popover
class="box-item"
content="加载最新字典"
placement="top-start"
>
<el-popover class="box-item" content="加载最新字典" placement="top-start">
<template #reference>
<el-button :icon="Refresh" size="small" circle @click="getDictOptions" class=""/>
<el-button :icon="Refresh" size="small" circle @click="getDictOptions" class="" />
</template>
</el-popover>
</div>

View File

@ -3,44 +3,44 @@
<div>
<ContentWrap>
<el-descriptions :column="3" border>
<el-descriptions-item label="产品名称">{{ product.name }}</el-descriptions-item>
<el-descriptions-item label="ProductKey">{{ product.productKey }}</el-descriptions-item>
<el-descriptions-item label="设备类型">
<dict-tag :type="DICT_TYPE.IOT_PRODUCT_DEVICE_TYPE" :value="product.deviceType" />
</el-descriptions-item>
<el-descriptions-item label="DeviceName">{{ device.deviceName }}</el-descriptions-item>
<el-descriptions-item label="备注名称">{{ device.nickname }}</el-descriptions-item>
<el-descriptions-item label="当前状态">
<dict-tag :type="DICT_TYPE.IOT_DEVICE_STATE" :value="device.state" />
</el-descriptions-item>
<el-descriptions-item label="创建时间">
{{ formatDate(device.createTime) }}
</el-descriptions-item>
<el-descriptions-item label="激活时间">
{{ formatDate(device.activeTime) }}
</el-descriptions-item>
<el-descriptions-item label="最后上线时间">
{{ formatDate(device.onlineTime) }}
</el-descriptions-item>
<el-descriptions-item label="最后离线时间">
{{ formatDate(device.offlineTime) }}
</el-descriptions-item>
<el-descriptions-item label="设备位置">
<template v-if="hasLocation">
<span class="mr-2">{{ device.longitude }}, {{ device.latitude }}</span>
<el-button type="primary" link @click="openMapDialog">
<Icon icon="ep:location" class="mr-1" />
查看地图
</el-button>
</template>
<span v-else class="text-[var(--el-text-color-secondary)]">暂无位置信息</span>
</el-descriptions-item>
<el-descriptions-item label="认证信息">
<el-button type="primary" @click="handleAuthInfoDialogOpen" plain size="small">
查看
<el-descriptions-item label="产品名称">{{ product.name }}</el-descriptions-item>
<el-descriptions-item label="ProductKey">{{ product.productKey }}</el-descriptions-item>
<el-descriptions-item label="设备类型">
<dict-tag :type="DICT_TYPE.IOT_PRODUCT_DEVICE_TYPE" :value="product.deviceType" />
</el-descriptions-item>
<el-descriptions-item label="DeviceName">{{ device.deviceName }}</el-descriptions-item>
<el-descriptions-item label="备注名称">{{ device.nickname }}</el-descriptions-item>
<el-descriptions-item label="当前状态">
<dict-tag :type="DICT_TYPE.IOT_DEVICE_STATE" :value="device.state" />
</el-descriptions-item>
<el-descriptions-item label="创建时间">
{{ formatDate(device.createTime) }}
</el-descriptions-item>
<el-descriptions-item label="激活时间">
{{ formatDate(device.activeTime) }}
</el-descriptions-item>
<el-descriptions-item label="最后上线时间">
{{ formatDate(device.onlineTime) }}
</el-descriptions-item>
<el-descriptions-item label="最后离线时间">
{{ formatDate(device.offlineTime) }}
</el-descriptions-item>
<el-descriptions-item label="设备位置">
<template v-if="hasLocation">
<span class="mr-2">{{ device.longitude }}, {{ device.latitude }}</span>
<el-button type="primary" link @click="openMapDialog">
<Icon icon="ep:location" class="mr-1" />
查看地图
</el-button>
</el-descriptions-item>
</el-descriptions>
</template>
<span v-else class="text-[var(--el-text-color-secondary)]">暂无位置信息</span>
</el-descriptions-item>
<el-descriptions-item label="认证信息">
<el-button type="primary" @click="handleAuthInfoDialogOpen" plain size="small">
查看
</el-button>
</el-descriptions-item>
</el-descriptions>
</ContentWrap>
<!-- 认证信息弹框 -->

View File

@ -36,7 +36,7 @@
inline-prompt
active-text="定时刷新"
inactive-text="定时刷新"
style="--el-switch-on-color: #13ce66"
:style="{ '--el-switch-on-color': '#13ce66' }"
/>
</el-form-item>
</el-form>

View File

@ -40,7 +40,7 @@
inline-prompt
active-text="定时刷新"
inactive-text="定时刷新"
style="--el-switch-on-color: #13ce66"
:style="{ '--el-switch-on-color': '#13ce66' }"
/>
</el-form-item>
</el-form>

View File

@ -308,9 +308,9 @@
</template>
</template>
</el-table-column>
<el-table-column label="设备状态" align="center" prop="status">
<el-table-column label="设备状态" align="center" prop="state">
<template #default="scope">
<dict-tag :type="DICT_TYPE.IOT_DEVICE_STATE" :value="scope.row.status" />
<dict-tag :type="DICT_TYPE.IOT_DEVICE_STATE" :value="scope.row.state" />
</template>
</el-table-column>
<el-table-column

View File

@ -131,22 +131,22 @@ onMounted(() => {
.terminal-card {
margin-top: 32px;
margin-bottom: 8px;
border-radius: 12px;
background-color: #1a1b26;
box-shadow: 0 10px 30px -10px rgba(0, 0, 0, 0.4);
border: 1px solid #24283b;
overflow: hidden;
font-family: 'Fira Code', 'JetBrains Mono', Consolas, Monaco, monospace;
background-color: #1a1b26;
border: 1px solid #24283b;
border-radius: 12px;
box-shadow: 0 10px 30px -10px rgb(0 0 0 / 40%);
}
.terminal-header {
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 16px;
background-color: #24283b;
border-bottom: 1px solid #16161e;
position: relative;
align-items: center;
justify-content: space-between;
}
.terminal-dots {
@ -160,53 +160,59 @@ onMounted(() => {
border-radius: 50%;
transition: transform 0.2s ease;
}
.dot:hover {
transform: scale(1.2);
}
.dot.red {
background-color: #f7768e;
box-shadow: 0 0 5px rgba(247, 118, 142, 0.4);
box-shadow: 0 0 5px rgb(247 118 142 / 40%);
}
.dot.yellow {
background-color: #e0af68;
box-shadow: 0 0 5px rgba(224, 175, 104, 0.4);
box-shadow: 0 0 5px rgb(224 175 104 / 40%);
}
.dot.green {
background-color: #9ece6a;
box-shadow: 0 0 5px rgba(158, 206, 106, 0.4);
box-shadow: 0 0 5px rgb(158 206 106 / 40%);
}
.terminal-title {
color: #a9b1d6;
position: absolute;
left: 50%;
font-size: 13px;
font-weight: 600;
letter-spacing: 0.8px;
position: absolute;
left: 50%;
color: #a9b1d6;
transform: translateX(-50%);
}
.terminal-copy-btn {
display: flex;
padding: 6px 12px;
font-family: inherit;
font-size: 12px;
color: #a9b1d6;
cursor: pointer;
background: transparent;
border: 1px solid #414868;
color: #a9b1d6;
border-radius: 6px;
padding: 6px 12px;
font-size: 12px;
cursor: pointer;
transition: all 0.25s cubic-bezier(0.175, 0.885, 0.32, 1.275);
display: flex;
align-items: center;
gap: 6px;
font-family: inherit;
}
.terminal-copy-btn:hover {
color: #1a1b26;
background: #bb9af7;
border-color: #bb9af7;
color: #1a1b26;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(187, 154, 247, 0.3);
box-shadow: 0 4px 12px rgb(187 154 247 / 30%);
}
.terminal-copy-btn:active {
transform: translateY(0);
}
@ -217,17 +223,17 @@ onMounted(() => {
.terminal-body {
padding: 20px;
color: #c0caf5;
font-size: 13px;
line-height: 1.6;
color: #c0caf5;
}
.terminal-desc {
color: #7dcfff;
padding-bottom: 16px;
margin-bottom: 16px;
font-family: var(--el-font-family);
font-size: 13px;
padding-bottom: 16px;
color: #7dcfff;
border-bottom: 1px dashed #292e42;
}
@ -237,9 +243,9 @@ onMounted(() => {
}
.terminal-code {
min-width: max-content;
margin: 0;
white-space: pre;
min-width: max-content;
}
.terminal-code code {
@ -267,13 +273,16 @@ onMounted(() => {
.terminal-code-wrapper::-webkit-scrollbar {
height: 8px;
}
.terminal-code-wrapper::-webkit-scrollbar-thumb {
background: #414868;
border-radius: 4px;
}
.terminal-code-wrapper::-webkit-scrollbar-thumb:hover {
background: #565f89;
}
.terminal-code-wrapper::-webkit-scrollbar-track {
background: transparent;
}

View File

@ -56,21 +56,28 @@ watch([urlPrefix, urlPath], () => {
config.value.url = fullUrl.value
})
const syncUrlFields = (url?: string) => {
if (url?.startsWith('https://')) {
urlPrefix.value = 'https://'
urlPath.value = url.substring(8)
} else if (url?.startsWith('http://')) {
urlPrefix.value = 'http://'
urlPath.value = url.substring(7)
} else {
urlPath.value = url ?? ''
}
}
watch(
() => config.value?.url,
(url) => syncUrlFields(url),
{ immediate: true }
)
/** 组件初始化 */
onMounted(() => {
if (!isEmpty(config.value)) {
// URL
if (config.value.url) {
if (config.value.url.startsWith('https://')) {
urlPrefix.value = 'https://'
urlPath.value = config.value.url.substring(8)
} else if (config.value.url.startsWith('http://')) {
urlPrefix.value = 'http://'
urlPath.value = config.value.url.substring(7)
} else {
urlPath.value = config.value.url
}
}
syncUrlFields(config.value.url)
return
}

View File

@ -35,9 +35,9 @@
>
{{ conditionIndex + 1 }}
</div>
<span class="text-12px font-500 text-[var(--el-text-color-primary)]"
>条件 {{ conditionIndex + 1 }}</span
>
<span class="text-12px font-500 text-[var(--el-text-color-primary)]">
条件 {{ conditionIndex + 1 }}
</span>
</div>
<el-button
type="danger"

View File

@ -141,6 +141,7 @@
<script setup lang="ts">
import { useVModel } from '@vueuse/core'
import { InfoFilled } from '@element-plus/icons-vue'
import { isEmptyVal } from '@/utils/is'
import {
IoTDataSpecsDataTypeEnum,
JSON_PARAMS_INPUT_CONSTANTS,
@ -329,7 +330,8 @@ const handleParamsChange = () => {
//
for (const param of paramsList.value) {
if (param.required && (!parsed[param.identifier] || parsed[param.identifier] === '')) {
const value = parsed[param.identifier]
if (param.required && isEmptyVal(value)) {
jsonError.value = JSON_PARAMS_INPUT_CONSTANTS.PARAM_REQUIRED_ERROR(param.name)
return
}

View File

@ -320,7 +320,7 @@ const onActionTypeChange = (action: Action, type: number, index: number) => {
action.params = ''
}
// identifier
if (action.identifier && type !== action.type) {
if (action.identifier) {
action.identifier = undefined
}
} else if (isAlertAction(type)) {

View File

@ -75,9 +75,9 @@
class="flex items-center gap-8px p-12px px-16px bg-[var(--el-fill-color-light)] rounded-6px border border-[var(--el-border-color-lighter)]"
>
<Icon icon="ep:timer" class="text-[var(--el-color-danger)] text-18px" />
<span class="text-14px font-500 text-[var(--el-text-color-primary)]"
>定时触发配置</span
>
<span class="text-14px font-500 text-[var(--el-text-color-primary)]">
定时触发配置
</span>
</div>
<!-- CRON 表达式配置 -->

View File

@ -438,12 +438,12 @@ export const IoTDeviceStatusEnum = {
// 在线状态
ONLINE: {
label: '在线',
value: 'online',
value: '1',
tagType: 'success'
},
OFFLINE: {
label: '离线',
value: 'offline',
value: '2',
tagType: 'danger'
},
// 启用状态

View File

@ -578,8 +578,10 @@ const getSkuTableRef = () => {
defineExpose({ generateTableData, validateSku, getSkuTableRef })
</script>
<style>
//
/*noinspection CssUnusedSymbol*/
/*
* 避免滚动条遮挡最后一行数据
* noinspection CssUnusedSymbol
*/
.el-table.tabNumWidth .el-scrollbar {
padding-bottom: 10px;
}

View File

@ -3,8 +3,8 @@
<el-table v-loading="loading" :data="list" show-overflow-tooltip>
<el-table-column label="#" width="55">
<template #default="{ row }">
<el-radio :value="row.id" v-model="selectedSkuId" @change="handleSelected(row)"
>&nbsp;
<el-radio :value="row.id" v-model="selectedSkuId" @change="handleSelected(row)">
&nbsp;
</el-radio>
</template>
</el-table-column>

View File

@ -136,11 +136,11 @@ const emitActivityChange = () => {
display: flex;
width: 60px;
height: 60px;
cursor: pointer;
border: 1px dashed var(--el-border-color-darker);
border-radius: 8px;
align-items: center;
justify-content: center;
cursor: pointer;
}
.spu-pic {

View File

@ -70,17 +70,17 @@
~ {{ formatDate(scope.row.endTime, 'YYYY-MM-DD') }}
</template>
</el-table-column>
<!-- <el-table-column label="商品图片" prop="spuName" min-width="80">-->
<!-- <template #default="scope">-->
<!-- <el-image-->
<!-- :src="scope.row.picUrl"-->
<!-- class="h-40px w-40px"-->
<!-- :preview-src-list="[scope.row.picUrl]"-->
<!-- preview-teleported-->
<!-- />-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- <el-table-column label="商品标题" prop="spuName" min-width="300" />-->
<!-- <el-table-column label="商品图片" prop="spuName" min-width="80">-->
<!-- <template #default="scope">-->
<!-- <el-image-->
<!-- :src="scope.row.picUrl"-->
<!-- class="h-40px w-40px"-->
<!-- :preview-src-list="[scope.row.picUrl]"-->
<!-- preview-teleported-->
<!-- />-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- <el-table-column label="商品标题" prop="spuName" min-width="300" />-->
<el-table-column label="活动状态" align="center" prop="status" min-width="100">
<template #default="scope">
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />

View File

@ -208,8 +208,8 @@ onBeforeUnmount(() => {
//transition: border-left 0.05s ease-in-out; /* */
.username {
min-width: 0;
max-width: 60%;
min-width: 0;
}
.last-message {
@ -218,27 +218,27 @@ onBeforeUnmount(() => {
.last-message,
.username {
display: -webkit-box;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}
}
.active {
background-color: rgba(128, 128, 128, 0.5); //
background-color: rgb(128 128 128 / 50%); //
}
.right-menu-ul {
position: absolute;
background-color: var(--app-content-bg-color);
width: 130px;
padding: 5px;
margin: 0;
list-style-type: none; /* 移除默认的项目符号 */
background-color: var(--app-content-bg-color);
border-radius: 12px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 阴影效果 */
width: 130px;
box-shadow: 0 2px 4px rgb(0 0 0 / 10%); /* 阴影效果 */
li {
padding: 8px 16px;

View File

@ -373,36 +373,36 @@ const showTime = computed(() => (item: KeFuMessageRespVO, index: number) => {
<style lang="scss" scoped>
.kefu {
background-color: var(--app-content-bg-color);
position: relative;
width: calc(100% - 300px - 260px);
background-color: var(--app-content-bg-color);
&::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 1px; /* 实际宽度 */
height: 100%;
background-color: var(--el-border-color);
content: '';
transform: scaleX(0.3); /* 缩小宽度 */
}
.kefu-header {
background-color: var(--app-content-bg-color);
position: relative;
display: flex;
background-color: var(--app-content-bg-color);
align-items: center;
justify-content: space-between;
&::before {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 1px; /* 初始宽度 */
background-color: var(--el-border-color);
content: '';
transform: scaleY(0.3); /* 缩小视觉高度 */
}
@ -413,30 +413,30 @@ const showTime = computed(() => (item: KeFuMessageRespVO, index: number) => {
}
&-content {
margin: 0;
padding: 10px;
position: relative;
height: 100%;
width: 100%;
height: 100%;
padding: 10px;
margin: 0;
.newMessageTip {
position: absolute;
bottom: 35px;
right: 35px;
background-color: var(--app-content-bg-color);
bottom: 35px;
padding: 10px;
border-radius: 30px;
font-size: 12px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 阴影效果 */
background-color: var(--app-content-bg-color);
border-radius: 30px;
box-shadow: 0 2px 4px rgb(0 0 0 / 10%); /* 阴影效果 */
}
.ss-row-left {
justify-content: flex-start;
.kefu-message {
background-color: #fff;
margin-left: 10px;
margin-top: 3px;
margin-left: 10px;
background-color: #fff;
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
border-bottom-left-radius: 10px;
@ -447,22 +447,22 @@ const showTime = computed(() => (item: KeFuMessageRespVO, index: number) => {
justify-content: flex-end;
.kefu-message {
background-color: rgb(206, 223, 255);
margin-right: 10px;
margin-top: 3px;
border-top-left-radius: 10px;
margin-right: 10px;
background-color: rgb(206 223 255);
border-bottom-right-radius: 10px;
border-bottom-left-radius: 10px;
border-top-left-radius: 10px;
}
}
//
.kefu-message {
color: #414141;
font-weight: 500;
padding: 5px 10px;
width: auto;
max-width: 50%;
padding: 5px 10px;
font-weight: 500;
color: #414141;
//text-align: left;
//display: inline-block !important;
//word-break: break-all;
@ -476,30 +476,30 @@ const showTime = computed(() => (item: KeFuMessageRespVO, index: number) => {
.date-message,
.system-message {
width: fit-content;
background-color: rgba(0, 0, 0, 0.1);
border-radius: 8px;
padding: 0 5px;
color: #fff;
font-size: 10px;
color: #fff;
background-color: rgb(0 0 0 / 10%);
border-radius: 8px;
}
}
.kefu-footer {
position: relative;
display: flex;
flex-direction: column;
height: auto;
margin: 0;
padding: 0;
margin: 0;
flex-direction: column;
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 1px; /* 初始宽度 */
background-color: var(--el-border-color);
content: '';
transform: scaleY(0.3); /* 缩小视觉高度 */
}
@ -510,13 +510,13 @@ const showTime = computed(() => (item: KeFuMessageRespVO, index: number) => {
}
::v-deep(textarea) {
resize: none;
background-color: var(--app-content-bg-color);
resize: none;
}
:deep(.el-input__wrapper) {
box-shadow: none !important;
border-radius: 0;
box-shadow: none !important;
}
::v-deep(.el-textarea__inner) {

View File

@ -173,31 +173,31 @@ const getUserData = async () => {
background-color: var(--app-content-bg-color);
&::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 1px; /* 实际宽度 */
height: 100%;
background-color: var(--el-border-color);
content: '';
transform: scaleX(0.3); /* 缩小宽度 */
}
&-header {
background-color: var(--app-content-bg-color);
position: relative;
display: flex;
background-color: var(--app-content-bg-color);
align-items: center;
justify-content: space-around;
&::before {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 1px; /* 初始宽度 */
background-color: var(--el-border-color);
content: '';
transform: scaleY(0.3); /* 缩小视觉高度 */
}
@ -207,45 +207,39 @@ const getUserData = async () => {
}
&-item {
height: 100%;
width: 100%;
position: relative;
width: 100%;
height: 100%;
&-activation::before {
content: '';
position: absolute; /* 绝对定位 */
top: 0;
left: 0;
right: 0;
bottom: 0; /* 覆盖整个元素 */
border-bottom: 2px solid rgba(128, 128, 128, 0.5); /* 边框样式 */
inset: 0; /* 覆盖整个元素 */
pointer-events: none; /* 确保点击事件不会被伪元素拦截 */
border-bottom: 2px solid rgb(128 128 128 / 50%); /* 边框样式 */
content: '';
}
&:hover::before {
content: '';
position: absolute; /* 绝对定位 */
top: 0;
left: 0;
right: 0;
bottom: 0; /* 覆盖整个元素 */
border-bottom: 2px solid rgba(128, 128, 128, 0.5); /* 边框样式 */
inset: 0; /* 覆盖整个元素 */
pointer-events: none; /* 确保点击事件不会被伪元素拦截 */
border-bottom: 2px solid rgb(128 128 128 / 50%); /* 边框样式 */
content: '';
}
}
}
&-content {
margin: 0;
padding: 0;
position: relative;
height: 100%;
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
&-tabs {
height: 100%;
width: 100%;
height: 100%;
}
}

View File

@ -24,8 +24,8 @@
</div>
<div class="pay-box flex justify-end pr-5px">
<div class="flex items-center">
<div class="discounts-title pay-color"
> {{ getMessageContent?.productCount }} 件商品,总金额:
<div class="discounts-title pay-color">
{{ getMessageContent?.productCount }} 件商品,总金额:
</div>
<div class="discounts-money pay-color">
{{ fenToYuan(getMessageContent?.payPrice) }}
@ -109,10 +109,10 @@ function formatOrderStatus(order: any) {
<style lang="scss" scoped>
.order-list-card-box {
border-radius: 10px;
padding: 10px;
background-color: rgb(128 128 128 / 30%); //
border: 1px var(--el-border-color) solid;
background-color: rgba(128, 128, 128, 0.3); //
border-radius: 10px;
.order-card-header {
height: 28px;
@ -123,8 +123,8 @@ function formatOrderStatus(order: any) {
span {
&:hover {
text-decoration: underline;
color: var(--left-menu-bg-active-color);
text-decoration: underline;
}
}
}
@ -144,9 +144,9 @@ function formatOrderStatus(order: any) {
}
.discounts-money {
font-family: OPPOSANS;
font-size: 16px;
line-height: normal;
font-family: OPPOSANS;
}
.pay-color {
@ -156,26 +156,26 @@ function formatOrderStatus(order: any) {
}
.warning-color {
color: #faad14;
font-size: 11px;
font-weight: bold;
color: #faad14;
}
.danger-color {
color: #ff3000;
font-size: 11px;
font-weight: bold;
color: #ff3000;
}
.success-color {
color: #52c41a;
font-size: 11px;
font-weight: bold;
color: #52c41a;
}
.info-color {
color: #999999;
font-size: 11px;
font-weight: bold;
color: #999;
}
</style>

View File

@ -68,21 +68,21 @@ const openDetail = (spuId: number) => {
<style lang="scss" scoped>
.button {
background-color: #007bff;
color: white;
border: none;
padding: 5px 10px;
color: white;
cursor: pointer;
background-color: #007bff;
border: none;
}
.product-warp {
display: flex;
width: 100%;
background-color: rgba(128, 128, 128, 0.3);
padding: 10px;
background-color: rgb(128 128 128 / 30%);
border: 1px solid var(--el-border-color);
border-radius: 8px;
display: flex;
align-items: center;
padding: 10px;
&-left {
width: 70px;
@ -98,14 +98,14 @@ const openDetail = (spuId: number) => {
flex: 1;
.description {
display: -webkit-box;
width: 100%;
overflow: hidden;
font-size: 16px;
font-weight: bold;
display: -webkit-box;
-webkit-line-clamp: 1; /* 显示一行 */
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1; /* 显示一行 */
}
.price {

Some files were not shown because too many files have changed in this diff Show More