Prechádzať zdrojové kódy

场景联动 - 未完成 代码同步

yukai 2 rokov pred
rodič
commit
076d30de3c

+ 16 - 0
src/api/scene/index.ts

@@ -0,0 +1,16 @@
+import { get, post, del, put, file } from '/@/utils/request';
+import getOrigin from '/@/utils/origin';
+const baseUrl = getOrigin(import.meta.env.VITE_SERVER_URL);
+
+export default {
+  manage: {
+    getFolder: () => get('/configure/folder/list'),
+    addFolder: (data: any) => post('/configure/folder/add', data),
+    getList: (data: any) => get('/configure/diagram/getList', data),
+    del: (id: number) => del('/configure/diagram/del', { id }),
+    deploy: (data: object) => post('/product/deploy', data),
+    undeploy: (data: object) => post('/product/undeploy', data),
+    add: (data: any) => post('/configure/diagram/add', data),
+    edit: (data: any) => post('/configure/diagram/edit', data),
+  }
+}

+ 82 - 0
src/views/iot/scene/list/index.vue

@@ -0,0 +1,82 @@
+<template>
+	<el-card shadow="hover">
+		<div class="search">
+			<el-form :inline="true" ref="queryRef">
+				<el-form-item label="场景名称:" prop="name">
+					<el-input v-model="params.keyWord" placeholder="请输入产品名称" clearable size="default" style="width: 240px"
+						@keyup.enter.native="getList" />
+				</el-form-item>
+				<el-form-item label="状态" prop="status" style="width: 200px;">
+					<el-select v-model="params.status" placeholder="发布状态" clearable size="default" style="width: 240px">
+						<el-option label="成功" :value="1" />
+						<el-option label="失败" :value="0" />
+					</el-select>
+				</el-form-item>
+				<el-form-item label="执行时间" prop="dateRange">
+					<el-date-picker v-model="params.dateRange" size="default" style="width: 240px" value-format="YYYY-MM-DD"
+						type="daterange" range-separator="-" start-placeholder="开始日期"
+						end-placeholder="结束日期"></el-date-picker>
+				</el-form-item>
+				<el-form-item>
+
+					<el-button size="default" type="primary" class="ml10" @click="getList()">
+						<el-icon>
+							<ele-Search />
+						</el-icon>
+						查询
+					</el-button>
+				</el-form-item>
+			
+			</el-form>
+		</div>
+		<el-table :data="tableData" style="width: 100%" row-key="id" v-loading="loading">
+			<el-table-column prop="id" label="ID" width="60" show-overflow-tooltip></el-table-column>
+			<el-table-column prop="name" label="场景名称" show-overflow-tooltip></el-table-column>
+			<el-table-column prop="name" label="动作类型" show-overflow-tooltip></el-table-column>
+			<el-table-column prop="name" label="执行状态" width="100" align="center">
+				<template #default="scope">
+					<el-tag type="success" size="small" v-if="scope.row.status">成功</el-tag>
+					<el-tag type="info" size="small" v-else>失败</el-tag>
+				</template>
+			</el-table-column> 
+			<el-table-column prop="createdAt" label="执行时间" min-width="100" align="center"></el-table-column>
+			<el-table-column label="操作" width="200" align="center">
+				<template #default="scope">
+					<el-button size="small" text type="primary" v-if="!scope.row.folderName"
+						@click="view(scope.row)">详情</el-button>
+					<el-button size="small" text type="danger" v-auth="'del'" @click="del(scope.row)">删除</el-button>
+				</template>
+			</el-table-column>
+		</el-table>
+		<pagination v-if="params.total" :total="params.total" v-model:page="params.pageNum" v-model:limit="params.pageSize"
+			@pagination="getList()" />
+	</el-card>
+</template>
+  
+<script lang="ts" setup>
+import api from '/@/api/scene';
+import { useSearch } from '/@/hooks/useCommon';
+import { ElMessageBox, ElMessage, FormInstance } from 'element-plus';
+import { ref } from 'vue';
+const queryRef = ref();
+const { params, tableData, getList, loading } = useSearch<any[]>(api.manage.getList, 'data', { keyWord: '' });
+getList();
+
+
+const view = (row: any) => {
+	
+};
+
+const del = (row: any) => {
+	ElMessageBox.confirm(`此操作将删除场景:“${row.name}”,是否继续?`, '提示', {
+		confirmButtonText: '确认',
+		cancelButtonText: '取消',
+		type: 'warning',
+	}).then(async () => {
+		await api.manage.del(row.id);
+		ElMessage.success('删除成功');
+		getList(1);
+	});
+};
+</script>
+  

+ 247 - 0
src/views/iot/scene/manage/component/condition.vue

@@ -0,0 +1,247 @@
+<template>
+  <div>
+    <div v-for="(item, index) in condition" :key="index">
+
+      <div v-if="index > 0"><el-divider>或满足以下条件</el-divider></div>
+      <div class="type-item">
+        <div class="flex-warp item_list">
+          <div v-for="(vo, i) in item.list" :key="i">
+
+            <div class="items">
+              <el-button
+                style="background: #fff; color: #000;border: 1px solid #d9cde3;margin-left: 10px;margin-right: 10px;"
+                v-if="i > 0">并且</el-button>
+
+              <el-popover placement="bottom" trigger="click">
+                <template #reference>
+                  <el-button style="background: #9adbff4d; color: #00a4fe;border: 1px solid #00a4fe4d;">{{ vo.param ||
+                    '请选择参数' }}</el-button>
+                </template>
+                <div class="popover-content">
+                  <ul>
+                    <li v-for="option in options" :key="option.value" @click="vo.param = option.value;">{{ option.label }}
+                    </li>
+                  </ul>
+                </div>
+              </el-popover>
+
+              <el-popover placement="bottom" trigger="click">
+                <template #reference>
+                  <el-button style="background: #a3caff4d; color: #2f54eb;border: 1px solid #2f54eb4d;">{{ vo.operator ||
+                    '操作符' }}</el-button>
+                </template>
+                <div class="popover-content">
+                  <ul>
+                    <li v-for="option in options" :key="option.value" @click="vo.operator = option.value;">{{ option.label
+                    }}</li>
+                  </ul>
+                </div>
+              </el-popover>
+
+              <el-popover placement="bottom" trigger="click">
+                <template #reference>
+                  <el-button style="background: #bc7dee1a; color: #692ca7;border: 1px solid #bc7dee80;">{{ vo.value ||
+                    '参数值' }}</el-button>
+                </template>
+                <div class="popover-content">
+                  <ul>
+                    <li v-for="option in options" :key="option.value" @click="vo.value = option.value;">{{ option.label }}
+                    </li>
+                  </ul>
+                </div>
+              </el-popover>
+
+              <el-icon size="16" v-if="i > 0" @click="DelSceneItem(index)" style="position: relative;top: -13px;">
+                <CircleClose />
+              </el-icon>
+
+            </div>
+
+          </div>
+
+          <div style="    padding-top: 12px;" @click="addSceneItem(index)">
+            <el-icon size="26">
+              <CirclePlus />
+            </el-icon>
+          </div>
+        </div>
+
+        <el-icon size="26" @click="delScene(index)" v-if="index > 0"
+          style="top: -69px;position: relative;font-size: 26px;right: 15px;">
+          <CircleClose />
+        </el-icon>
+      </div>
+
+    </div>
+
+    <div class="mt15"><el-button @click="addScene()">增加触发条件</el-button></div>
+
+
+
+
+
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { PropType, ref } from 'vue'
+import { CirclePlus, CircleClose, Right } from '@element-plus/icons-vue';
+
+const options = [
+  { label: '选项一', value: 'option1' },
+  { label: '选项二', value: 'option2' },
+  { label: '选项三', value: 'option3' },
+];
+
+interface IConditionItem {
+  param?: string;
+  operator?: string;
+  value?: string;
+}
+
+interface IValueType {
+  list: IConditionItem[] ;
+}
+
+const props = defineProps({
+
+  condition: {
+    type: Array as PropType<IValueType[]> | undefined,
+    default: () => []
+  },
+  operate_index: {
+    type: Number,
+    default: () => 0
+  }
+})
+
+const addSceneItem = (index: any | number) => {
+  props.condition[index].list.push({
+    'param': '',
+    'operator': '',
+    'value': ''
+  })
+}
+
+const DelSceneItem = (index: any | number) => {
+  props.condition[index].list.splice(index, 1);
+}
+
+
+const addScene = () => {
+  props.condition.push({
+    'list': [{
+      'param': '',
+      'operator': '',
+      'value': ''
+    }],
+
+  });
+};
+const delScene = (index: number) => {
+  props.condition.splice(index, 1);
+}
+
+</script>
+<style scoped lang="scss">
+::v-deep .el-divider__text {
+  background: #f6f6f6 !important;
+
+}
+
+//先保留
+// ::v-deep .condition_value{
+//    .el-input__wrapper {
+//       width: 120px;
+//       background: #9adbff4d !important;
+//       box-shadow:0px !important;
+//     .el-input__inner{
+//       color: #00a4fe;
+//       text-align: center;
+//     }
+//     .el-input__wrapper .is-focus{
+//       box-shadow:0px !important;
+//     }
+//     .el-input__inner::placeholder{
+//       color: #00a4fe;
+//     }
+//   }
+// }
+.popover-content {
+  padding: 0px;
+}
+
+.popover-content ul {
+  list-style-type: none;
+  padding: 0;
+}
+
+.popover-content li {
+  cursor: pointer;
+  padding: 5px;
+
+}
+
+.popover-content li:hover {
+  background-color: #e6f7ff;
+}
+
+.type-item {
+  margin-top: 15px;
+
+  .conicon {
+    cursor: pointer;
+  }
+
+  .item_list {
+    background: #fff;
+    border: 1px dashed;
+
+    .items {
+      padding: 10px;
+
+      .el-select {
+        width: 99px;
+      }
+
+      .el-select--default {
+        --el-select-border-color-hover: var(--el-border-color-hover);
+        --el-select-disabled-border: var(--el-disabled-border-color);
+        --el-select-font-size: var(--el-font-size-base);
+        --el-select-close-hover-color: var(--el-text-color-secondary);
+        --el-select-input-color: var(--el-text-color-placeholder);
+        --el-select-multiple-input-color: var(--el-text-color-regular);
+        --el-select-input-focus-border-color: var(--el-color-primary);
+        --el-select-input-font-size: 14px;
+      }
+
+
+    }
+
+
+  }
+
+  .title {
+    height: 40px;
+
+    .icon {
+      margin-left: 2px;
+      margin-right: 10px;
+      width: 5px;
+      height: 20px;
+      background-color: #315efb;
+    }
+  }
+
+  .product {
+
+    .el-form-item {
+      margin-left: 30px;
+      margin-bottom: 10px;
+      margin-top: 10px;
+    }
+  }
+
+}
+</style>
+

+ 231 - 0
src/views/iot/scene/manage/component/sceneItem.vue

@@ -0,0 +1,231 @@
+<template>
+  <div class="type-item">
+    <div v-for="(item, index) in sceneList" :key="index" class="item " :class="index > 0 ? 'biankang' : ''">
+      <div class="conicon" style="width: 100%; text-align: right; position: relative; right: -8px; top: -8px; color: red"
+        v-if="index > 0">
+        <el-icon @click="delScene(index)">
+          <CircleClose />
+        </el-icon>
+      </div>
+      <div class="font16">场景定义</div>
+      <div class="title flex">
+        <div class="icon"></div>触发规则
+      </div>
+      <div class="product flex flex-warp">
+
+        <el-form-item label="产品:" prop="product_key">
+          <el-select v-model="item.product_key" filterable placeholder="请选择产品">
+            <el-option v-for="it in sourceData" :key="it.key" :label="it.name" :value="it.key">
+              <span style="float: left">{{ it.name }}</span>
+              <span style="float: right; font-size: 13px">{{ it.key }}</span>
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="设备:" prop="device_key">
+          <el-select v-model="item.device_key" filterable placeholder="请选择设备">
+            <el-option v-for="it in sourceData" :key="it.key" :label="it.name" :value="it.key">
+              <span style="float: left">{{ it.name }}</span>
+              <span style="float: right; font-size: 13px">{{ it.key }}</span>
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="触发类型:" prop="type">
+          <el-select v-model="item.type" filterable placeholder="请选择触发类型">
+            <el-option v-for="it in sourceData" :key="it.key" :label="it.name" :value="it.key">
+              <span style="float: left">{{ it.name }}</span>
+              <span style="float: right; font-size: 13px">{{ it.key }}</span>
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="定时请求">
+          <div style="display:flex">
+            <el-input v-model="item.cronExpression" placeholder="请输入cron表达式" />
+            <el-dialog v-model="dialogVisible" title="选择Cron规则" width="60%">
+              <vue3cron @handlelisten="handlelisten" :type="index" @close="cronclose"></vue3cron>
+            </el-dialog>
+            <el-button type="success"  @click="showCron()" style="margin-left: 5px;">设置</el-button>
+
+          </div>
+        </el-form-item>
+        <el-form-item label="属性:" prop="type">
+          <el-select v-model="item.type" filterable placeholder="请选择触发类型">
+            <el-option v-for="it in sourceData" :key="it.key" :label="it.name" :value="it.key">
+              <span style="float: left">{{ it.name }}</span>
+              <span style="float: right; font-size: 13px">{{ it.key }}</span>
+            </el-option>
+          </el-select>
+        </el-form-item>
+      </div>
+
+      <div class="title flex">
+        <div class="icon"></div>触发条件 <div class="ml10"> <el-switch v-model="item.where" />
+        </div>
+      </div>
+        <Condition :condition="item.condition" :operate_index="index"  v-if="item.where"></Condition>
+    </div>
+    <div>
+      <div class="edit">
+        <el-button type="primary" :icon="DocumentAdd" @click="addScene()">新增场景定义</el-button>
+      </div>
+    </div>
+
+
+
+
+ 
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { PropType, ref,unref  } from 'vue'
+import { DocumentAdd, CircleClose, Right } from '@element-plus/icons-vue';
+import vue3cron from '/@/components/vue3cron/vue3cron.vue';
+
+import Condition from './condition.vue';
+
+const dialogVisible=ref();
+
+interface IConditionItem {
+  param?: string;
+  operator?: string;
+  value?: string;
+}
+
+interface IValueType {
+  type?: string;
+  product_key?: string;
+  device_key?: string;
+  where?: string;
+  cronExpression?: string;
+  condition?: {
+    list?: IConditionItem[] ;
+  }[];
+}
+
+
+
+interface testIValueType {
+  key: string;
+  name?: string;
+
+}
+
+const props = defineProps({
+
+  sceneList: {
+    type: Array as PropType<IValueType[]>,
+    default: () => []
+  },
+  sourceData: {
+    type: Array as PropType<testIValueType[]>,
+    default: () => [{
+      'key': 'test',
+      'name': '测试',
+    }, {
+      'key': 'test',
+      'name': '测试',
+    }, {
+      'key': 'test',
+      'name': '测试',
+    }, {
+      'key': 'test',
+      'name': '测试',
+    }, {
+      'key': 'test',
+      'name': '测试',
+    }]
+  }
+})
+
+
+const addScene = () => {
+  props.sceneList.push({
+    'product_key': '',
+    'device_key': '',
+    'type': '',
+    'condition':[{
+								'list': [{
+											'param': '',
+											'operator': '',
+											'value': ''
+										}]
+							}]
+  });
+  console.log(props.sceneList);
+};
+const delScene = (index: number) => {
+  props.sceneList.splice(index, 1);
+}
+const setNull = (row: any, key: string, val: string) => {
+  if (!val) row[key] = null
+}
+const handlelisten = (e: any) => {
+  props.sceneList[e.type].cronExpression=e.cron;
+ 
+};
+const showCron = () => {
+  dialogVisible.value = true;
+
+};
+const cronclose = () => {
+  dialogVisible.value = false;
+}
+</script>
+<style scoped lang="scss">
+
+.type-item {
+  margin-top: 15px;
+
+  .edit {
+    margin-top: 15px;
+    margin-left: 10px;
+    color: #2041d4;
+  }
+
+  .conicon {
+    width: 55px;
+    height: 25px;
+
+    font-size: 28px;
+    line-height: 28px;
+    cursor: pointer;
+  }
+
+  .item {
+    padding: 20px;
+    background-color: #f2f3f5;
+    margin-top: 20px;
+
+  }
+
+  .biankang {
+
+    border: 1px dashed;
+    border-radius: 10px;
+  }
+
+
+  .title {
+    height: 40px;
+
+    .icon {
+      margin-left: 2px;
+      margin-right: 10px;
+      width: 5px;
+      height: 20px;
+      background-color: #315efb;
+    }
+  }
+
+  .product {
+
+    .el-form-item {
+      margin-left: 30px;
+      margin-bottom: 10px;
+      margin-top: 10px;
+    }
+  }
+
+}
+</style>
+

+ 152 - 0
src/views/iot/scene/manage/detail.vue

@@ -0,0 +1,152 @@
+<template>
+	<el-card class="system-dic-container" style="position: relative;">
+		<div class="content">
+			<div class="flex cont_box">
+				<div class="font26">场景名称:店里车间场景</div>
+				<div class="pro-status"><span :class="developer_status == 2 ? 'on' : 'off'"></span>{{ developer_status == 2
+					? '启用' : '禁用' }}</div>
+			</div>
+
+			<div class="flex">
+				<div class="desc">场景描述:这个组队电力车间整个场景进行模拟计算</div>
+				<div class="edit" @click="addOrEdit({})"><el-link type="primary"> <el-icon>
+							<EditPen color="#409eff" />
+						</el-icon>修改</el-link></div>
+			</div>
+
+		</div>
+
+	</el-card>
+
+	
+	<EditForm ref="editFormRef" @getList="getDetail()"></EditForm>
+</template>
+<script lang="ts">
+import { toRefs, reactive, onMounted, ref, defineComponent } from 'vue';
+import { ElMessage } from 'element-plus';
+import type { TabsPaneContext } from 'element-plus'
+import { useRoute, useRouter } from 'vue-router';
+import { EditPen, DocumentAdd } from '@element-plus/icons-vue';
+import SceneItem from './component/sceneItem.vue';
+import EditForm from './edit.vue';
+import api from '/@/api/network';
+
+const editFormRef = ref();
+const sceneList = [{
+	'product_key': '',
+	'device_key': '',
+	'type': '',
+	'where': false,
+	'condition': [{
+		'list': [{
+			'param': '',
+			'operator': '',
+			'value': ''
+		}]
+	}]
+}];
+
+
+export default defineComponent({
+	components: { EditPen, EditForm, DocumentAdd, SceneItem },
+	setup(props, context) {
+		const route = useRoute();
+		const router = useRouter();
+		const state = reactive({
+			developer_status: 2,
+			detail: {},
+			sceneList: [{
+				'product_key': '',
+				'device_key': '',
+				'type': '',
+				'action': [{}],
+				'where': false,
+				'condition': [{
+					'list': [{
+						'param': '',
+						'operator': '',
+						'value': ''
+					}]
+				}]
+			}],
+
+		});
+		const activeName = ref('first')
+		const getDetail = () => {
+			const id = route.params && route.params.id;
+			api.server.getDetail({ "id": id }).then((res: any) => {
+				state.detail = res
+			})
+		};
+		const addOrEdit = async (row?: any) => {
+			editFormRef.value.open(row);
+		};
+
+		const freshData = () => {
+			getDetail()
+			ElMessage.success('刷新成功');
+		};
+		const toEdit = () => {
+			router.push(`/iotmanager/network/server/edit/${route.params && route.params.id}`)
+		};
+		onMounted(() => {
+			// getDetail()
+		});
+		const handleClick = (tab: TabsPaneContext, event: Event) => {
+			// console.log(tab, event)
+		}
+
+
+
+		return {
+			toEdit,
+			addOrEdit,
+
+			editFormRef,
+			activeName,
+			freshData,
+			getDetail,
+			handleClick,
+			...toRefs(props),
+			...toRefs(state),
+		};
+	},
+});
+</script>
+
+<style scoped lang="scss">
+.desc {
+	margin-top: 15px;
+}
+
+.edit {
+	line-height: 40px;
+	margin-top: 15px;
+	margin-left: 30px;
+}
+
+.cont_box .pro-status {
+	line-height: 40px;
+	margin-left: 30px;
+	margin-top: 5px;
+
+	.on {
+		background: #52c41a;
+	}
+
+	.off {
+		background: #c41a1a;
+	}
+
+	span {
+		position: relative;
+		top: -1px;
+		display: inline-block;
+		width: 6px;
+		height: 6px;
+		vertical-align: middle;
+		border-radius: 50%;
+		margin-right: 5px;
+	}
+}
+</style>

+ 79 - 0
src/views/iot/scene/manage/edit.vue

@@ -0,0 +1,79 @@
+<template>
+	<el-dialog
+		class="api-edit"
+		v-model="showDialog"
+		:title="`${formData.id ? '编辑场景' : '新增场景'}`"
+		width="600px"
+		:close-on-click-modal="false"
+		:close-on-press-escape="false"
+	>
+		<el-form ref="formRef" :model="formData" :rules="ruleForm" label-width="80px">
+			<el-form-item label="场景描述" prop="name">
+				<el-input v-model="formData.name" placeholder="请输入场景描述" />
+			</el-form-item>
+			<el-form-item label="场景描述" prop="desc">
+				<el-input v-model="formData.desc" type="textarea" :rows="3" />
+			</el-form-item>
+		</el-form>
+		<template #footer>
+			<div class="dialog-footer">
+				<el-button @click="showDialog = false">取消</el-button>
+				<el-button type="primary" @click="onSubmit">确定</el-button>
+			</div>
+		</template>
+	</el-dialog>
+</template>
+
+<script lang="ts" setup>
+import { ref, reactive, nextTick } from 'vue';
+import api from '/@/api/scene';
+import { ruleRequired } from '/@/utils/validator';
+import { ElMessage } from 'element-plus';
+
+const emit = defineEmits(['getList']);
+
+const showDialog = ref(false);
+const formRef = ref();
+
+const baseForm = {
+	id: undefined,
+	name: '',
+	desc: '',
+};
+
+const formData = reactive({
+	...baseForm,
+});
+
+const ruleForm = {
+	name: [ruleRequired('场景名称不能为空')],
+};
+
+const onSubmit = async () => {
+	await formRef.value.validate();
+
+	const theApi = formData.id ? api.manage.edit : api.manage.add;
+
+	await theApi(formData);
+
+	ElMessage.success('操作成功');
+	resetForm();
+	showDialog.value = false;
+	emit('getList');
+};
+
+const resetForm = async () => {
+	Object.assign(formData, { ...baseForm });
+	formRef.value && formRef.value.resetFields();
+};
+
+const open = async (row: any) => {
+	resetForm();
+	showDialog.value = true;
+	nextTick(() => {
+		Object.assign(formData, { ...row });
+	});
+};
+
+defineExpose({ open });
+</script>

+ 140 - 0
src/views/iot/scene/manage/index.vue

@@ -0,0 +1,140 @@
+<template>
+	<el-card shadow="hover">
+		<div class="search">
+			<el-form :inline="true" ref="queryRef">
+				<el-form-item label="场景名称:" prop="name">
+					<el-input v-model="params.keyWord" placeholder="请输入产品名称" clearable size="default" style="width: 240px"
+						@keyup.enter.native="getList" />
+				</el-form-item>
+				<el-form-item label="运行状态" prop="status" style="width: 200px;">
+					<el-select v-model="params.status" placeholder="运行状态" clearable size="default" style="width: 240px">
+						<el-option label="启用" :value="1" />
+						<el-option label="禁用" :value="0" />
+					</el-select>
+				</el-form-item>
+			
+				<el-form-item>
+
+					<el-button size="default" type="primary" class="ml10" @click="getList()">
+						<el-icon>
+							<ele-Search />
+						</el-icon>
+						查询
+					</el-button>
+				</el-form-item>
+				<el-form-item>
+					<el-button type="success" v-auth="'add'" @click="addOrEdit()">
+						<el-icon>
+							<ele-FolderAdd />
+						</el-icon>
+						新增场景
+					</el-button>
+
+				</el-form-item>
+			</el-form>
+		</div>
+		<el-table :data="tableData" style="width: 100%" row-key="id" v-loading="loading">
+			<el-table-column prop="id" label="ID" width="60" show-overflow-tooltip></el-table-column>
+			<el-table-column prop="name" label="场景名称" show-overflow-tooltip></el-table-column>
+			<el-table-column prop="name" label="描述" show-overflow-tooltip></el-table-column>
+			<el-table-column prop="name" label="运行状态" width="100" align="center">
+				<template #default="scope">
+					<el-tag type="success" size="small" v-if="scope.row.status">启用</el-tag>
+					<el-tag type="info" size="small" v-else>禁用</el-tag>
+				</template>
+			</el-table-column> 
+			<el-table-column prop="createdAt" label="创建时间" min-width="100" align="center"></el-table-column>
+			<el-table-column label="操作" width="200" align="center">
+				<template #default="scope">
+					<el-button size="small" text type="primary" v-if="!scope.row.folderName"
+						@click="toDetail(scope.row.id)">详情</el-button>
+					<el-button size="small" text type="warning" v-auth="'edit'" @click="addOrEdit(scope.row)">编辑</el-button>
+					<el-button size="small" text type="success" @click="onActionStatus(scope.row)" v-if="scope.row.status==0" v-auth="'startOrStop'">启用</el-button>
+          		   <el-button size="small" text type="primary" @click="onActionStatus(scope.row)" v-if="scope.row.status>0" v-auth="'startOrStop'">停用</el-button>
+					<el-button size="small" text type="danger" v-auth="'del'" @click="del(scope.row)">删除</el-button>
+				</template>
+			</el-table-column>
+		</el-table>
+		<pagination v-if="params.total" :total="params.total" v-model:page="params.pageNum" v-model:limit="params.pageSize"
+			@pagination="getList()" />
+		<EditForm ref="editFormRef" @getList="getList()"></EditForm>
+	</el-card>
+</template>
+  
+<script lang="ts" setup>
+import api from '/@/api/scene';
+import { useSearch } from '/@/hooks/useCommon';
+import { ElMessageBox, ElMessage, FormInstance } from 'element-plus';
+import getOrigin from '/@/utils/origin'
+import EditForm from './edit.vue';
+import { ref } from 'vue';
+import { useRouter } from 'vue-router';
+
+const queryRef = ref();
+const router = useRouter();
+
+const editFormRef = ref();
+
+const { params, tableData, getList, loading } = useSearch<any[]>(api.manage.getList, 'data', { keyWord: '' });
+
+getList();
+/** 重置按钮操作 */
+const resetQuery = (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	formEl.resetFields();
+	getList();
+};
+const toDetail = (id: number) => {
+      router.push(`/iotmanager/scene/manage/detail/${id}`)
+};
+function getTokenUrl(url: string) {
+	const tokenUrl = import.meta.env.VITE_TOPO_URL
+	return getOrigin(tokenUrl + url)
+}
+
+const view = (row: any) => {
+	const url = getTokenUrl('#/show/' + row.id);
+	window.open(url);
+};
+
+const addOrEdit = async (row?: any) => {
+	// const url = getTokenUrl('#/editor/new');
+	// window.open(url);
+	if (row) {
+		editFormRef.value.open(row);
+		return;
+	} else {
+		editFormRef.value.open();
+	}
+};
+
+const edit = (row: any) => {
+	const url = getTokenUrl('#/editor/' + row.id);
+	window.open(url);
+};
+const onActionStatus = (item: any) => {
+      if (item.status == 0) {
+        api.manage.deploy({ id: item.id }).then((res: any) => {
+			getList();
+          ElMessage.success(res.message || '操作成功');
+        });
+      } else {
+        api.manage.undeploy({ id: item.id }).then((res: any) => {
+			getList();
+          ElMessage.success(res.message || '操作成功');
+        });
+      }
+    }
+const del = (row: any) => {
+	ElMessageBox.confirm(`此操作将删除图形:“${row.name}”,是否继续?`, '提示', {
+		confirmButtonText: '确认',
+		cancelButtonText: '取消',
+		type: 'warning',
+	}).then(async () => {
+		await api.manage.del(row.id);
+		ElMessage.success('删除成功');
+		getList();
+	});
+};
+</script>
+