heyujie
2022-07-29 90427ad7b5e73aaee2eb376080547787d25dc2bb
suanfa app mange
2个文件已修改
6个文件已添加
2629 ■■■■■ 已修改文件
src/components/LeftNav.vue 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router.ts 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/AlgrithmManage/BaseAlgorithm.vue 240 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/AlgrithmManage/BaseAlgorithmEdit.vue 287 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/AlgrithmManage/PageAlgorithm.vue 301 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/AlgrithmManage/PageAlgorithmEdit.vue 925 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/AppManage/AppEdit.vue 646 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/AppManage/AppManage.vue 170 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/LeftNav.vue
@@ -65,14 +65,17 @@
          <span>管理员报表</span>
        </template>
        <el-menu-item-group> </el-menu-item-group>
      </el-submenu>
      </el-submenu> -->
      <el-submenu index="5">
        <template slot="title">
          <i class="iconfont">&#xe654;</i>
          <span>算法管理</span>
        </template>
        <el-menu-item-group> </el-menu-item-group>
        <el-menu-item-group>
          <el-menu-item index="/Layout/PageAlgorithm">应用算法</el-menu-item>
          <el-menu-item index="/Layout/BaseAlgorithm">基础算法</el-menu-item>
        </el-menu-item-group>
      </el-submenu>
      <el-submenu index="6">
@@ -80,8 +83,10 @@
          <i class="iconfont">&#xe656;</i>
          <span>应用管理</span>
        </template>
        <el-menu-item-group> </el-menu-item-group>
      </el-submenu> -->
        <el-menu-item-group>
          <el-menu-item index="/Layout/AppManage">应用管理</el-menu-item>
        </el-menu-item-group>
      </el-submenu>
    </el-menu>
  </div>
</template>
src/router.ts
@@ -16,6 +16,12 @@
import AddProduct from './views/operateManage/productManage/AddProduct.vue'
import EquipmentList from './views/equipmentManage/equipmentList/index.vue'
import EquipmentDetail from './views/equipmentManage/equipmentDetail/index.vue'
import AppManage from './views/AppManage/AppManage.vue'
import AppEdit from './views/AppManage/AppEdit.vue'
import BaseAlgorithm from "./views/AlgrithmManage/BaseAlgorithm.vue";
import PageAlgorithm from "./views/AlgrithmManage/PageAlgorithm.vue";
import PageAlgorithmEdit from './views/AlgrithmManage/PageAlgorithmEdit.vue';
import BaseAlgorithmEdit from './views/AlgrithmManage/BaseAlgorithmEdit.vue';
import MobileLogin from "./views/MobileLogin.vue";
import BindPhone from "./views/BindPhone.vue";
@@ -77,7 +83,7 @@
          name: "UserList",
          component: UserList
        },
         {
        {
          path: "UserDetail",
          name: "UserDetail",
          component: UserDetail
@@ -97,12 +103,12 @@
          name: "ModelList",
          component: ModelList
        },
         {
        {
          path: "AddModel",
          name: "AddModel",
          component: AddModel
        },
         {
        {
          path: "ProductList",
          name: "ProductList",
          component: ProductList
@@ -122,11 +128,44 @@
          name: "EquipmentList",
          component: EquipmentList
        },
          {
        {
          path: "EquipmentDetail",
          name: "EquipmentDetail",
          component: EquipmentDetail
        },
        {
          path: "AppManage",
          name: "AppManage",
          component: AppManage
        },
        {
          path: "AppEdit/:appId",
          name: "appEdit",
          component: AppEdit,
          props: true
        },
        {
          path: "PageAlgorithm",
          name: "PageAlgorithm",
          component: PageAlgorithm,
        },
        {
          path: "BaseAlgorithm",
          name: "BaseAlgorithm",
          component: BaseAlgorithm,
        },
        {
          path: "PageAlgorithmEdit/:action/:id",
          name: "PageAlgorithmEdit",
          component: PageAlgorithmEdit,
          props: true
        },
        {
          path: "BaseAlgorithmEdit/:action/:id",
          name: "BaseAlgorithmEdit",
          component: BaseAlgorithmEdit,
          props: true
        },
      ]
    }
  ]
src/views/AlgrithmManage/BaseAlgorithm.vue
New file
@@ -0,0 +1,240 @@
<template>
  <div class="right-main">
    <div class="top-title">
      <p>基础算法列表</p>
    </div>
    <div class="control-bar">
      <div class="line-one">
        <div class="right-fixed">
          <el-button type="primary" size="small" @click="createBaseAlg"
            >添加</el-button
          >
        </div>
      </div>
    </div>
    <div class="table-area">
      <el-table
        id="multipleTable"
        ref="multipleTable"
        :data="baseSdkData"
        tooltip-effect="dark"
        :fit="true"
      >
        <!-- <el-table-column type="selection" width="30"></el-table-column> -->
        <el-table-column label="序号" width="68">
          <template slot-scope="scope">{{
            scope.$index + 1 + (page - 1) * size
          }}</template>
        </el-table-column>
        <el-table-column
          prop="name"
          label="基础算法名称"
          min-width="200"
          show-overflow-tooltip
          sortable
        >
          <template slot-scope="scope">
            <div v-if="isBaseAlgEdit && curEditIndex == scope.$index">
              <el-input size="small" v-model="baseSdkItem.sdk_type"></el-input>
            </div>
            <div v-else>{{ scope.row.sdk_type }}</div>
          </template>
        </el-table-column>
        <el-table-column label="更新时间" width="200">
          <template slot-scope="scope">
            <div>{{ getTime(scope.row.update_time) }}</div>
          </template>
        </el-table-column>
        <el-table-column
          prop="version"
          label="最新版本号"
          width="200"
          sortable
        ></el-table-column>
        <!-- <el-table-column
          prop="source"
          label="基础算法组件"
          min-width="130"
          show-overflow-tooltip
          sortable
        >
          <template slot-scope="scope">
            <div v-if="isBaseAlgEdit && curEditIndex == scope.$index">
              <file-uploader
                single
                uploadPlaceholder="上传算法组件"
                url="/data/api-f/file/upload"
                @complete="onFileUpload"
                @file-added="onFileAdded"
              />
            </div>
            <div v-else>{{scope.row.component_name}}</div>
          </template>
        </el-table-column>-->
        <el-table-column label="操作" width="200">
          <template slot-scope="scope">
            <!-- <div v-if="isBaseAlgEdit && curEditIndex == scope.$index">
              <span class="cursor-pointer" @click="cancle(scope.row)">取消</span>
              <span class="cursor-pointer" @click="saveRowSdk(scope.row)">保存</span>
            </div>-->
            <div>
              <span
                class="cursor-pointer"
                @click="editBaseAlg(scope.row, scope.$index)"
                >编辑</span
              >
              <span class="cursor-pointer" @click="delSdk(scope.row)"
                >删除</span
              >
            </div>
          </template>
        </el-table-column>
      </el-table>
      <div>
        <el-pagination
          @current-change="refresh"
          @size-change="handleSizeChange"
          :current-page="page"
          :page-sizes="[8, 10, 15, 20, 25]"
          :page-size="size"
          layout="total, sizes, prev, pager, next, jumper"
          :total="total"
        ></el-pagination>
      </div>
    </div>
  </div>
</template>
<script>
import request from "@/api/index";
// import { findAllBaseAlg, deleteBaseAlg } from "@/api/algorithm";
import { getFilePath } from "@/api/utils";
export default {
  data() {
    return {
      size: 10,
      page: 1,
      total: 0,
      baseSdkData: [],
      baseSdkItem: {
        sdk_type: "",
        component_name: "",
        component_path: "",
      },
      //baseSdkItem:{},
      curEditRow: {},
      isBaseAlgEdit: false,
      curEditIndex: 0,
    };
  },
  methods: {
    newBaseSdk() {
      return {
        sdk_type: "",
        component_name: "",
        component_path: "",
      };
    },
    async renderTableList() {
      let data = await findAllBaseAlg({ page: this.page, size: this.size });
      if (data.code == 200) {
        this.total = data.data.total;
        this.baseSdkData = data.data.list;
      }
    },
    saveRowSdk(row) {
      this.isBaseAlgEdit = false;
      let params = {
        id: this.baseSdkItem.id,
        component_name: this.curEditRow.component_name,
        component_path: this.curEditRow.component_path,
        sdk_type: this.baseSdkItem.sdk_type,
      };
      saveBaseAlg(params)
        .then((res) => {
          this.$notify({
            type: "success",
            message: "保存成功!",
            duration: 2500,
            offset: 57,
          });
          this.renderTableList();
        })
        .catch((e) => {
          console.log(e);
        });
    },
    cancle(row) {
      if (!row.id) {
        this.baseSdkData.splice(this.baseSdkData.length - 1, 1);
        this.isBaseAlgEdit = false;
        return;
      }
      this.isBaseAlgEdit = false;
    },
    editBaseAlg(row, index) {
      this.$router.push({ path: `/Layout/BaseAlgorithmEdit/edit/${row.id}` });
      // if (this.isBaseAlgEdit) return;
      // this.isBaseAlgEdit = true;
      // this.curEditIndex = index;
      // this.baseSdkItem = JSON.parse(JSON.stringify(row));
    },
    delSdk(row) {
      this.$confirm("确定删除该项吗?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
        center: true,
      })
        .then(() => {
          deleteBaseAlg(row.id).then((res) => {
            this.$message({
              type: "success",
              message: "删除成功!",
            });
            this.renderTableList();
          });
        })
        .catch((e) => {
          console.log(e);
        });
    },
    createBaseAlg() {
      this.$router.push({ path: "/Layout/BaseAlgorithmEdit/create/alg" });
      // if (this.isBaseAlgEdit) return;
      // this.baseSdkItem = this.newBaseSdk();
      // this.baseSdkData.push(this.baseSdkItem);
      // this.isBaseAlgEdit = true;
      // this.curEditIndex = this.baseSdkData.length - 1;
    },
    refresh(page) {
      this.page = page;
      this.renderTableList();
    },
    handleSizeChange(size) {
      this.size = size;
      this.renderTableList();
    },
    getTime(time) {
      return (
        time.substring(0, 4) +
        "-" +
        time.substring(4, 6) +
        "-" +
        time.substring(6, 8)
      );
    },
    // rowClick(row, column, ev){
    //   this.curEditRow = JSON.parse(JSON.stringify(row));
    // }
  },
  mounted() {
    this.renderTableList();
  },
};
</script>
src/views/AlgrithmManage/BaseAlgorithmEdit.vue
New file
@@ -0,0 +1,287 @@
<template>
  <div class="right-main">
    <div class="bread-crumb">
      <span class="prev-title">
        <router-link to="/layout/BaseAlgorithm">基础算法列表</router-link>
      </span>
      <span class="devide"></span>
      <span class="cur-title">{{ action == "create" ? "添加" : "编辑" }}</span>
    </div>
    <div style="min-height: calc(100vh - 150px); background: #fff">
      <el-form :model="algForm" ref="algForm" label-width="120px">
        <div class="base-info info-block">
          <div class="info-header">
            <span class="title">基本信息</span>
          </div>
          <div class="info-body">
            <div class="left">
              <el-form-item label="基础算法名称:" prop="sdk_name">
                <!-- <el-input v-model="algForm.sdk_name" size="small"></el-input> -->
                <i>{{ algForm.sdk_name }}</i>
              </el-form-item>
            </div>
          </div>
        </div>
      </el-form>
      <div class="base-info info-block">
        <div class="info-header">
          <span class="title">算法版本</span>
          <div class="toAdd" @click="toAddVersion">
            <i class="el-icon-circle-plus-outline"></i>
            <span>添加</span>
          </div>
        </div>
        <div class="info-body">
          <el-table :data="versionInfo" style="width: 100%" border>
            <el-table-column
              type="index"
              width="50"
              label="序号"
              align="center"
            ></el-table-column>
            <el-table-column
              prop="version_show"
              width="200"
              label="版本号"
              align="center"
            >
              <template slot-scope="scope">
                <div>
                  <span>{{ scope.row.version_show }}</span>
                </div>
              </template>
            </el-table-column>
            <el-table-column
              prop="content"
              width="500"
              label="版本更新内容"
              header-align="center"
            >
              <template slot-scope="scope">
                <div v-if="isVersionEdit && curEditIndex == scope.$index">
                  <el-input v-model="editData.content" size="mini"></el-input>
                </div>
                <div v-else>
                  <span>{{ scope.row.content }}</span>
                </div>
              </template>
            </el-table-column>
            <el-table-column
              width="240"
              label="更新时间"
              align="center"
              prop="updateTime"
            ></el-table-column>
            <el-table-column
              prop="updateUserName"
              width="150"
              label="更新人"
              align="center"
            ></el-table-column>
            <el-table-column width="330" label="附件" align="center">
              <template slot-scope="scope">
                <div
                  v-if="
                    isVersionEdit &&
                    curEditIndex == scope.$index &&
                    !scope.row.id
                  "
                >
                  <file-uploader
                    single
                    uploadPlaceholder="上传算法文件"
                    url="/data/api-f/file/upload"
                    @complete="onFileUpload"
                    @file-added="onFileAdded"
                  />
                </div>
                <div v-else>{{ scope.row.component_name }}</div>
              </template>
            </el-table-column>
            <el-table-column label="操作" align="center" width="124">
              <template slot-scope="scope">
                <div v-if="isVersionEdit && curEditIndex == scope.$index">
                  <span class="cursor-pointer" @click="cancel(scope.row)"
                    >取消</span
                  >
                  <span
                    class="cursor-pointer"
                    @click="saveRowVersion(scope.row)"
                    >保存</span
                  >
                </div>
                <div class="operation" v-else>
                  <i
                    class="el-icon-edit"
                    @click="edit(scope.row, scope.$index)"
                  ></i>
                  <i
                    class="el-icon-remove-outline"
                    @click="remove(scope.row)"
                  ></i>
                </div>
              </template>
            </el-table-column>
          </el-table>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import FileUploader from "@/components/subComponents/FileUpload/index";
import { getFilePath } from "@/api/utils";
// import {
//   findBaseAlgVersions,
//   saveBaseAlg,
//   deleteVersion,
// } from "@/api/algorithm";
export default {
  components: { FileUploader },
  props: ["action", "id"],
  data() {
    return {
      copy_id: this.id,
      tableParams: {
        page: 1,
        sdkBaseId: this.id,
        size: 10,
      },
      total: 0,
      algForm: {
        sdk_name: "",
      },
      editData: {},
      versionInfo: [],
      isVersionEdit: false,
      curEditIndex: 0,
      curEditRow: {},
    };
  },
  mounted() {
    if (this.action == "create") {
      this.copy_id = "";
    }
    if (this.copy_id) {
      this.getVersionList();
    }
  },
  methods: {
    async getVersionList() {
      let res = await findBaseAlgVersions(this.tableParams);
      this.versionInfo = res.data.list;
      this.total = res.data.total;
      this.algForm.sdk_name = res.data.list[0] && res.data.list[0].sdk_type;
    },
    newVersion() {
      return {
        version: "",
        content: "",
        updateTime: "",
        person: "",
        component_name: "",
        component_path: "",
      };
    },
    toAddVersion() {
      if (this.isVersionEdit) return;
      this.editData = this.newVersion();
      this.versionInfo.push(this.editData);
      this.isVersionEdit = true;
      this.curEditIndex = this.versionInfo.length - 1;
    },
    edit(row, index) {
      this.isVersionEdit = true;
      this.curEditIndex = index;
      this.editData = JSON.parse(JSON.stringify(row));
    },
    onFileAdded() {},
    onFileUpload(param) {
      this.curEditRow.component_name = param.filename;
      getFilePath(param).then((res) => {
        if (res.code == 200) {
          this.curEditRow.component_path = res.data;
        }
      });
    },
    cancel(row) {
      this.isVersionEdit = false;
      if (!row.id) {
        this.versionInfo.splice(this.versionInfo.length - 1, 1);
      }
    },
    saveRowVersion(row) {
      let params = {
        component_name: row.id
          ? row.component_name
          : this.curEditRow.component_name,
        component_path: row.id
          ? row.component_name
          : this.curEditRow.component_path,
        content: this.editData.content,
        id: row.id || "",
        sdkBaseId: this.copy_id,
      };
      saveBaseAlg(params)
        .then((res) => {
          if (res.success) {
            this.$notify({
              type: "success",
              message: "保存成功!",
              duration: 2500,
              offset: 57,
            });
            this.isVersionEdit = false;
            this.getVersionList();
          }
        })
        .catch((e) => {
          if (e && e.status == 401) {
            return;
          }
          this.$notify({
            type: "error",
            message: e.msg,
            duration: 2500,
            offset: 57,
          });
        });
    },
    async remove(row) {
      if (this.versionInfo.length == 1) {
        this.$confirm(
          "请谨慎操作,删除后此基础算法所关联的应用将无法使用, 是否继续?",
          "提示",
          {
            confirmButtonText: "确定",
            cancelButtonText: "取消",
          }
        )
          .then(async () => {
            const res = await deleteVersion(row.id);
            if (res && res.success) {
              this.$notify({
                type: "success",
                message: "删除成功",
              });
              this.getVersionList();
            }
          })
          .catch(() => {});
      } else {
        const res = await deleteVersion(row.id);
        if (res && res.success) {
          this.$notify({
            type: "success",
            message: "删除成功",
          });
          this.getVersionList();
        }
      }
    },
  },
};
</script>
<style></style>
src/views/AlgrithmManage/PageAlgorithm.vue
New file
@@ -0,0 +1,301 @@
<template>
  <div class="right-main">
    <div class="top-title">
      <p>应用算法列表</p>
    </div>
    <div class="control-bar">
      <div class="line-one">
        <div class="screening">
          <label>基础算法</label>
          <el-select v-model="sdk_type" size="small" placeholder="请选择">
            <el-option
              v-for="item in baseSdkList"
              :key="item.id"
              :label="item.sdk_type"
              :value="item.sdk_type"
              :title="item.sdk_type"
            ></el-option>
          </el-select>
        </div>
        <div class="screening">
          <label>SO</label>
          <el-select v-model="rule_so" size="small" placeholder="请选择">
            <el-option
              v-for="(item, index) in soList"
              :key="index"
              :label="item"
              :value="item"
              :title="item"
            ></el-option>
          </el-select>
        </div>
        <div class="screening">
          <label>算法名称</label>
          <el-input placeholder="请输入" prefix-icon="el-icon-search" v-model="inputText" size="small"></el-input>
        </div>
        <div class="screening">
          <el-button type="primary" class="btn-search" plain @click="renderTableList(1)" size="small">搜索</el-button>
          <el-button class="btn-reset" @click="clearSearch" size="small">重置</el-button>
        </div>
        <div class="right-fixed">
          <el-button class="cursor-pointer" type="primary" size="small" @click="createPageAlg">添加</el-button>
        </div>
      </div>
    </div>
    <div class="table-area">
      <el-table
        v-loading="tableLoading"
        :data="pageAlgsData"
        tooltip-effect="dark"
        :fit="true"
        :default-sort="{ prop: 'createTime', order: 'descending' }"
      >
        <!-- <el-table-column type="selection" width="30"></el-table-column> -->
        <el-table-column label="序号" width="68">
          <template slot-scope="scope">{{ scope.$index + 1 + (page - 1) * size }}</template>
        </el-table-column>
        <el-table-column prop="id" label="算法编号" min-width="160" sortable></el-table-column>
        <el-table-column
          prop="sdk_name"
          label="应用算法名称"
          min-width="200"
          show-overflow-tooltip
          sortable
        ></el-table-column>
        <el-table-column
          prop="sdk_type"
          label="基础算法名称"
          min-width="150"
          show-overflow-tooltip
          sortable
        ></el-table-column>
        <el-table-column prop="rule_so" label="SO名称" min-width="130" show-overflow-tooltip sortable></el-table-column>
        <el-table-column
          prop="version"
          label="最新版本号"
          min-width="140"
          show-overflow-tooltip
          sortable
        ></el-table-column>
        <el-table-column label="最后更新时间" min-width="180" sortable>
          <template slot-scope="scope">
            <div>{{ scope.row.update_time || scope.row.create_time }}</div>
          </template>
        </el-table-column>
        <el-table-column
          label="更新人"
          width="140"
          prop="updateUserName"
          show-overflow-tooltip
          sortable
        ></el-table-column>
        <el-table-column label="操作" min-width="120">
          <template slot-scope="scope">
            <span class="cursor-pointer" @click="edit(scope.row)">编辑</span>
            <span class="cursor-pointer" @click="deletePageAlg(scope.row)">删除</span>
          </template>
        </el-table-column>
      </el-table>
      <div>
        <el-pagination
          @current-change="refresh"
          @size-change="handleSizeChange"
          :current-page="page"
          :page-sizes="[5, 10, 15, 20, 25]"
          :page-size="size"
          layout="total, sizes, prev, pager, next, jumper"
          :total="total"
        ></el-pagination>
      </div>
    </div>
  </div>
</template>
<script>
// import { findAllBaseAlg, getAllSO, getAllPageAlg, delPageAlg } from "@/api/algorithm"
import request from "@/api/index"
export default {
  data() {
    return {
      baseSdkList: [],
      soList: [],
      tableHeight: window.innerHeight - 350,
      sdk_type: "",
      page: 1,
      size: 10,
      total: 0,
      rule_so: "",
      inputText: "",
      pageAlgsData: [],
      tableLoading: false
    }
  },
  methods: {
    renderTableList(v) {
      this.tableLoading = true
      getAllPageAlg({
        inputText: this.inputText,
        page: v === 1 ? 1 : this.page,
        rule_so: this.rule_so,
        sdk_type: this.sdk_type,
        size: this.size
      })
        .then((res) => {
          if (res.code == 200) {
            this.pageAlgsData = res.data.list
            this.total = res.data.total
            this.tableLoading = false
            if (res.data.total <= this.size) {
              this.page = 1
            }
          }
        })
        .catch((e) => {
          this.tableLoading = false
          if (e && e.status == 401) {
            return
          }
          this.$notify({
            type: "error",
            message: "数据获取失败,请稍后重试!",
            duration: 2500,
            offset: 57
          })
        })
    },
    getAllBaseSDK() {
      findAllBaseAlg().then((res) => {
        if (res.code == 200) {
          this.baseSdkList = res.data.list
        }
      })
    },
    getSOList() {
      getAllSO().then((res) => {
        if (res.success) {
          this.soList = res.data.list
        }
      })
    },
    refresh(page) {
      this.page = page
      this.renderTableList()
    },
    handleSizeChange(size) {
      this.size = size
      this.renderTableList()
    },
    edit(row) {
      this.$router.push({ path: `/Layout/PageAlgorithmEdit/edit/${row.id}` })
    },
    deletePageAlg(row) {
      this.$confirm("确定删除该项吗?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
        center: true
      })
        .then(() => {
          delPageAlg(row.id).then((res) => {
            if (res.code == 200) {
              this.$message({
                type: "success",
                message: "删除成功!"
              })
              this.renderTableList()
            }
          })
        })
        .catch((e) => {
          console.log(e)
        })
    },
    createPageAlg() {
      this.$router.push({ path: "/Layout/PageAlgorithmEdit/create/alg" })
    },
    clearSearch() {
      this.sdk_type = ""
      this.inputText = ""
      this.rule_so = ""
      this.renderTableList()
    }
  },
  mounted() {
    this.getAllBaseSDK()
    this.getSOList()
    this.renderTableList()
  }
}
</script>
<style lang="scss">
.manageOrder {
  width: 100%;
  height: 100%;
  .orderTop {
    width: calc(100% - 60px);
    height: 30px;
    background: #fff;
    padding: 15px 30px;
    p {
      font-family: "PingFangSC-Regular";
      text-align: left;
      font-size: 18px;
      line-height: 30px;
      font-weight: 600;
    }
  }
  .orderBody {
    width: calc(100% - 40px);
    height: calc(100% - 100px);
    padding: 20px;
    background: #f0f2f5;
    .top {
      background-image: linear-gradient(-180deg, #ffffff 13%, #e9ebf2 100%);
      height: 76px;
      width: 100%;
      padding: 5px 22px;
      box-sizing: border-box;
      text-align: left;
      // line-height: 55px;
      white-space: nowrap;
      overflow-x: auto;
      overflow-y: hidden;
      .p-label,
      .p-task,
      .p-level,
      .p-date,
      .p-input,
      .p-clear {
        display: inline-block;
        padding-right: 10px;
        box-sizing: border-box;
        margin-top: 20px;
        b:hover {
          min-width: 100px;
          color: #2249b4;
        }
        .el-input__inner {
          border-radius: 3px;
        }
      }
      .clear-searching {
        cursor: pointer;
        text-decoration: underline;
        width: 40px;
        font-size: 13px;
        color: #3d68e1;
      }
    }
    .orderList {
      width: calc(100% - 30px);
      height: calc(100% - 106px);
      background: #fff;
      padding: 15px;
      border-radius: 5px;
      // overflow-y: scroll
    }
  }
}
</style>
src/views/AlgrithmManage/PageAlgorithmEdit.vue
New file
@@ -0,0 +1,925 @@
<template>
  <div class="right-main pageAlg">
    <div class="bread-crumb">
      <span class="prev-title">
        <router-link to="/layout/PageAlgorithm">算法列表</router-link>
      </span>
      <span class="devide"></span>
      <span class="cur-title">{{ action == "create" ? "添加" : "编辑" }}</span>
    </div>
    <div style="min-height: calc(100vh - 150px); background: #fff">
      <el-form
        :model="algForm"
        ref="algForm"
        :rules="rules"
        label-width="120px"
        v-loading="loading"
      >
        <div class="base-info info-block">
          <div class="info-header">
            <span class="title">基本信息</span>
          </div>
          <div class="info-body">
            <div class="left">
              <el-form-item label="应用算法名称" prop="sdk_name">
                <el-input v-model="algForm.sdk_name" size="small"></el-input>
              </el-form-item>
              <el-form-item label="对应基础算法" prop="sdk_type">
                <el-select v-model="algForm.sdk_type" size="small">
                  <el-option
                    :label="item.sdk_type"
                    :value="item.sdk_type"
                    v-for="item in baseSdkList"
                    :key="item.id"
                  ></el-option>
                </el-select>
              </el-form-item>
              <el-form-item label="对应SO" prop="rule_so">
                <el-input v-model="algForm.rule_so" size="small"></el-input>
              </el-form-item>
            </div>
            <div class="right">
              <el-form-item label="算法logo">
                <el-upload
                  class="avatar-uploader"
                  drag
                  action="https://jsonplaceholder.typicode.com/posts/"
                  :show-file-list="false"
                  :http-request="uploadAlgLogo"
                  :on-success="onSuccess"
                  :before-upload="beforeUpload"
                >
                  <el-image
                    v-if="algForm.iconBlob"
                    :src="
                      algForm.iconBlob.indexOf(',') > 0
                        ? algForm.iconBlob
                        : `data:image/png;base64,${algForm.iconBlob}`
                    "
                    style="width: 100%; height: 100%"
                    fit="contain"
                  ></el-image>
                  <i v-else class="el-icon-plus avatar-uploader-icon"></i>
                  <div class="el-upload__text">
                    将图片拖到此处,或
                    <em>点击上传</em>
                  </div>
                </el-upload>
                <span class="second-icon-desc">其它风格应用logo:</span>
                <el-upload
                  class="avatar-uploader"
                  drag
                  action="https://jsonplaceholder.typicode.com/posts/"
                  :show-file-list="false"
                  :http-request="uploadAlgLogo2"
                  :on-success="onSuccess"
                  :before-upload="beforeUpload"
                >
                  <el-image
                    v-if="algForm.iconBlob2"
                    :src="
                      algForm.iconBlob2.indexOf(',') > 0
                        ? algForm.iconBlob2
                        : `data:image/png;base64,${algForm.iconBlob2}`
                    "
                    style="width: 100%; height: 100%"
                    fit="contain"
                  ></el-image>
                  <i v-else class="el-icon-plus avatar-uploader-icon"></i>
                  <div class="el-upload__text">
                    将图片拖到此处,或
                    <em>点击上传</em>
                  </div>
                </el-upload>
              </el-form-item>
              <el-form-item label="是否跟踪" prop="enTrack">
                <el-switch v-model="algForm.enTrack" size="small"></el-switch>
              </el-form-item>
            </div>
          </div>
        </div>
        <div class="base-info info-block">
          <div class="info-header">
            <span class="title">参数设置</span>
            <div class="toAdd" @click="toAddParam">
              <i class="el-icon-circle-plus-outline"></i>
              <span>添加</span>
            </div>
          </div>
          <div class="info-body">
            <el-table :data="algParams" border style="width: 100%">
              <el-table-column
                type="index"
                width="50"
                label="序号"
                align="center"
              ></el-table-column>
              <el-table-column
                prop="arg_type"
                label="目标/标签"
                width="110"
                align="center"
              >
                <template slot-scope="scope">
                  <div>
                    <el-select v-model="scope.row.arg_type" size="mini">
                      <el-option label="目标" value="target"></el-option>
                      <el-option label="标签" value="label"></el-option>
                    </el-select>
                  </div>
                </template>
              </el-table-column>
              <el-table-column
                prop="alias"
                label="算法参数"
                width="140"
                align="center"
              >
                <template slot-scope="scope">
                  <div>
                    <el-input v-model="scope.row.alias" size="mini"></el-input>
                  </div>
                </template>
              </el-table-column>
              <el-table-column
                prop="name"
                label="应用参数名称"
                width="150"
                align="center"
              >
                <template slot-scope="scope">
                  <div>
                    <el-input v-model="scope.row.name" size="mini"></el-input>
                  </div>
                </template>
              </el-table-column>
              <el-table-column
                prop="operators"
                label="符号关系"
                width="200"
                align="center"
              >
                <template slot-scope="scope">
                  <div>
                    <el-select
                      v-model="scope.row.operators"
                      size="mini"
                      multiple
                      collapse-tags
                    >
                      <el-option
                        :label="item.name"
                        :value="item"
                        v-for="item in operatorList"
                        :key="item.id"
                      ></el-option>
                    </el-select>
                  </div>
                </template>
              </el-table-column>
              <el-table-column
                prop="default_value"
                label="参数值"
                width="120"
                align="center"
              >
                <template slot-scope="scope">
                  <div>
                    <el-input
                      v-model="scope.row.default_value"
                      size="mini"
                    ></el-input>
                  </div>
                </template>
              </el-table-column>
              <el-table-column
                prop="unit"
                label="单位"
                width="90"
                align="center"
              >
                <template slot-scope="scope">
                  <div>
                    <el-input v-model="scope.row.unit" size="mini"></el-input>
                  </div>
                </template>
              </el-table-column>
              <el-table-column
                prop="range"
                label="参数区间"
                width="100"
                align="center"
              >
                <template slot-scope="scope">
                  <div>
                    <el-input v-model="scope.row.range" size="mini"></el-input>
                  </div>
                </template>
              </el-table-column>
              <el-table-column
                prop="type"
                label="值类型"
                width="110"
                align="center"
              >
                <template slot-scope="scope">
                  <div>
                    <el-select v-model="scope.row.type" size="mini">
                      <el-option label="值" value="value"></el-option>
                      <el-option label="被选项" value="option"></el-option>
                    </el-select>
                  </div>
                </template>
              </el-table-column>
              <el-table-column
                prop="isConfigurable"
                label="是否可配置"
                width="100"
                align="center"
              >
                <template slot-scope="scope">
                  <div>
                    <el-select
                      v-model="scope.row.config.isConfigurable"
                      size="mini"
                    >
                      <el-option label="是" :value="true"></el-option>
                      <el-option label="否" :value="false"></el-option>
                    </el-select>
                  </div>
                </template>
              </el-table-column>
              <el-table-column
                prop="isMulti"
                label="是否多选"
                width="80"
                align="center"
              >
                <template slot-scope="scope">
                  <div>
                    <el-select v-model="scope.row.config.isMulti" size="mini">
                      <el-option label="是" :value="true"></el-option>
                      <el-option label="否" :value="false"></el-option>
                    </el-select>
                  </div>
                </template>
              </el-table-column>
              <el-table-column
                prop="isOptional"
                label="是否可选项"
                width="100"
                align="center"
              >
                <template slot-scope="scope">
                  <div>
                    <el-select
                      v-model="scope.row.config.isOptional"
                      size="mini"
                    >
                      <el-option label="是" :value="true"></el-option>
                      <el-option label="否" :value="false"></el-option>
                    </el-select>
                  </div>
                </template>
              </el-table-column>
              <el-table-column
                prop="isShow"
                label="是否可见"
                width="80"
                align="center"
              >
                <template slot-scope="scope">
                  <div>
                    <el-select v-model="scope.row.config.isShow" size="mini">
                      <el-option label="是" :value="true"></el-option>
                      <el-option label="否" :value="false"></el-option>
                    </el-select>
                  </div>
                </template>
              </el-table-column>
              <el-table-column label="操作" align="center">
                <template slot-scope="scope">
                  <div class="operation">
                    <el-tooltip content="上移一位">
                      <i
                        class="el-icon-top"
                        @click="moveUp(scope.$index)"
                        v-show="scope.$index != 0"
                      ></i>
                    </el-tooltip>
                    <el-tooltip content="移除该项配置,须保存表单后方能生效">
                      <i
                        class="el-icon-remove-outline"
                        @click="removeParam(scope.$index)"
                      ></i>
                    </el-tooltip>
                  </div>
                </template>
              </el-table-column>
            </el-table>
          </div>
          <el-form-item size="large" class="form-end">
            <el-button size="small" @click="backForm">取消</el-button>
            <el-button type="primary" size="small" @click="saveForm"
              >保存</el-button
            >
          </el-form-item>
        </div>
      </el-form>
      <div class="base-info info-block">
        <div class="info-header">
          <span class="title">算法版本</span>
          <div class="toAdd" @click="toAddVersion">
            <i class="el-icon-circle-plus-outline"></i>
            <span>添加</span>
          </div>
        </div>
        <div class="info-body">
          <el-table :data="versionInfo" style="width: 100%" border>
            <el-table-column
              type="index"
              width="50"
              label="序号"
              align="center"
            ></el-table-column>
            <el-table-column
              prop="version"
              width="150"
              label="版本号"
              align="center"
            >
              <template slot-scope="scope">
                <div v-if="isVersionEdit && curEditIndex == scope.$index">
                  <el-input v-model="editData.version" size="mini"></el-input>
                </div>
                <div v-else>
                  <span>{{ scope.row.version }}</span>
                </div>
              </template>
            </el-table-column>
            <el-table-column
              prop="content"
              width="500"
              label="版本更新内容"
              header-align="center"
            >
              <template slot-scope="scope">
                <div v-if="isVersionEdit && curEditIndex == scope.$index">
                  <el-input v-model="editData.content" size="mini"></el-input>
                </div>
                <div v-else>
                  <span>{{ scope.row.content }}</span>
                </div>
              </template>
            </el-table-column>
            <el-table-column width="290" label="更新时间" align="center">
              <template slot-scope="scope">
                <div>{{ scope.row.update_time || scope.row.create_time }}</div>
              </template>
            </el-table-column>
            <el-table-column
              prop="updateUserName"
              width="150"
              label="更新人"
              align="center"
            ></el-table-column>
            <el-table-column width="250" label="附件" align="center">
              <template slot-scope="scope">
                <div v-if="isVersionEdit && curEditIndex == scope.$index">
                  <file-uploader
                    single
                    uploadPlaceholder="上传算法文件"
                    url="/data/api-f/file/upload"
                    @complete="onFileUpload"
                    @file-added="onFileAdded"
                  />
                </div>
                <div v-else>{{ scope.row.component_name }}</div>
              </template>
            </el-table-column>
            <el-table-column label="操作" align="center">
              <template slot-scope="scope">
                <div v-if="isVersionEdit && curEditIndex == scope.$index">
                  <span class="cursor-pointer" @click="cancel(scope.row)"
                    >取消</span
                  >
                  <span
                    class="cursor-pointer"
                    @click="saveRowVersion(scope.row)"
                    >保存</span
                  >
                </div>
                <div class="operation" v-else>
                  <i
                    class="el-icon-edit"
                    @click="edit(scope.row, scope.$index)"
                  ></i>
                  <i
                    class="el-icon-remove-outline"
                    @click="remove(scope.row)"
                  ></i>
                </div>
              </template>
            </el-table-column>
          </el-table>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
// import {
//   savePageAlg,
//   findAllBaseAlg,
//   savePageAlgVersion,
//   delPageAlgVersion,
//   showPageAlgDetail,
// } from "@/api/algorithm";
import { findDicByType } from "@/api/product";
import { getFilePath } from "@/api/utils";
import FileUploader from "@/components/subComponents/FileUpload/index";
export default {
  components: {
    FileUploader,
  },
  props: ["action", "id"],
  data() {
    return {
      copy_id: this.id,
      loading: false,
      algForm: {
        sdk_name: "",
        sdk_type: "", //基础算法
        iconBlob: "",
        iconBlob2: "",
        rule_so: "",
        enTrack: true,
      },
      baseSdkList: [],
      operatorList: [],
      rules: {
        sdk_name: [
          { required: true, message: "请输入算法名称", trigger: "blur" },
          { min: 1, max: 15, message: "长度在1到15个字符", trigger: "blur" },
        ],
        sdk_type: [
          { required: true, message: "请选择基础算法", trigger: "change" },
        ],
        rule_so: [{ required: true, message: "请输入so", trigger: "blur" }],
      },
      algParams: [],
      algParam: {
        sort: 0,
        arg_type: "target",
        alias: "",
        name: "",
        operators: [],
        range: "",
        default_value: "",
        unit: "",
        type: "value",
        config: {
          isConfigurable: true,
          isMulti: true,
          isOptional: true,
          isShow: true,
        },
      },
      versionInfo: [],
      versionParam: {
        version: "",
        content: "",
        updateTime: "",
        person: "",
        component_name: "",
        component_path: "",
      },
      editData: {},
      curEditVersion: {},
      isVersionEdit: false,
      curEditIndex: 0,
      curEditRow: {},
    };
  },
  mounted() {
    this.getAllBaseSDK();
    this.getOperatorList();
    if (this.action == "create") {
      //this.id = ''
      this.copy_id = "";
    }
    if (this.copy_id) {
      this.getPageDetail();
    }
  },
  methods: {
    newVersion() {
      return {
        version: "",
        content: "",
        updateTime: "",
        person: "",
        component_name: "",
        component_path: "",
      };
    },
    backForm() {
      //this.getPageDetail();
      //this.$router.push('/layout/AppManage');
      this.$router.go(-1);
    },
    getPageDetail() {
      //回显页面参数
      showPageAlgDetail({ id: this.copy_id }).then((res) => {
        if (res.code == 200) {
          this.algForm.enTrack = res.data.sdkInfo.enTrack;
          this.algForm.iconBlob = res.data.sdkInfo.iconBlob;
          this.algForm.iconBlob2 = res.data.sdkInfo.iconBlob2;
          this.algForm.rule_so = res.data.sdkInfo.rule_so;
          this.algForm.sdk_type = res.data.sdkInfo.sdk_type;
          this.algForm.sdk_name = res.data.sdkInfo.sdk_name;
          this.algParams = res.data.sdkInfo.argDef;
          this.algParams.forEach((arg) => {
            arg.operators = arg.operators.map((item) => {
              return {
                name: item.name,
                value: item.operator,
              };
            });
          });
          this.versionInfo = res.data.versions;
        }
      });
    },
    getAllBaseSDK() {
      findAllBaseAlg().then((res) => {
        if (res.code == 200) {
          this.baseSdkList = res.data.list;
        }
      });
    },
    getOperatorList() {
      //this.operatorList
      findDicByType({ type: "RULECOMPUTE" }).then((res) => {
        if (res.code == 200) {
          this.operatorList = res.data.dics;
        }
      });
    },
    toAddParam() {
      let algTemp = JSON.parse(JSON.stringify(this.algParam));
      algTemp.sort = this.algParams.length + 1;
      this.algParams.push(algTemp);
    },
    toAddVersion() {
      if (this.isVersionEdit) return;
      //let versionTemp = JSON.parse(JSON.stringify(this.versionParam));
      // let versionTemp = this.newVersion();
      // this.versionInfo.push(versionTemp);
      this.editData = this.newVersion();
      this.versionInfo.push(this.editData);
      this.isVersionEdit = true;
      this.curEditIndex = this.versionInfo.length - 1;
    },
    beforeUpload() {},
    uploadAlgLogo(params) {
      let file = params.file;
      let fileReader = new FileReader();
      if (file) {
        fileReader.readAsDataURL(file);
      }
      fileReader.onload = () => {
        this.algForm.iconBlob = fileReader.result;
      };
    },
    uploadAlgLogo2(params) {
      let file = params.file;
      let fileReader = new FileReader();
      if (file) {
        fileReader.readAsDataURL(file);
      }
      fileReader.onload = () => {
        this.algForm.iconBlob2 = fileReader.result;
      };
    },
    onSuccess() {},
    moveUp(curIndex) {
      let lastOne = JSON.parse(JSON.stringify(this.algParams[curIndex - 1]));
      let curOne = JSON.parse(JSON.stringify(this.algParams[curIndex]));
      //this.algParams.splice(curIndex,1,curIndex-1);
      this.$set(this.algParams, curIndex, lastOne);
      this.$set(this.algParams, curIndex - 1, curOne);
      this.algParams[curIndex - 1].sort = curIndex;
      this.algParams[curIndex].sort = curIndex + 1;
    },
    removeParam(index) {
      // this.$notify({
      //   type:'info',
      //   message:'请在保存后查看最新内容'
      // });
      this.algParams.splice(index, 1);
    },
    remove(row) {
      this.$confirm("确定删除该项吗?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
        center: true,
      })
        .then(() => {
          delPageAlgVersion(row.id).then((res) => {
            if (res.code == 200) {
              this.$message({
                type: "success",
                message: "删除成功!",
              });
              this.getPageDetail();
            }
          });
        })
        .catch((e) => {
          console.log(e);
        });
    },
    cancel(row) {
      this.isVersionEdit = false;
      if (!row.id) {
        this.versionInfo.splice(this.versionInfo.length - 1, 1);
      }
    },
    // rowClick (row, column, ev) {
    //   this.curEditRow = JSON.parse(JSON.stringify(row));
    // },
    saveForm() {
      this.$refs["algForm"].validate((valid) => {
        if (valid) {
          //处理operators
          this.algParams.forEach((param) => {
            param.operators = param.operators.map((item) => {
              return {
                name: item.name,
                operator: item.value,
              };
            });
          });
          let params = {
            argDef: this.algParams,
            enTrack: this.algForm.enTrack,
            iconBlob: this.algForm.iconBlob,
            iconBlob2: this.algForm.iconBlob2,
            id: this.copy_id,
            rule_so: this.algForm.rule_so,
            sdk_name: this.algForm.sdk_name,
            sdk_type: this.algForm.sdk_type,
          };
          let warning = "";
          params.argDef.forEach((item) => {
            if (
              item.alias === "" ||
              item.name === "" ||
              item.operators.length === 0 ||
              item.default_value === "" ||
              item.unit === "" ||
              item.range === ""
            ) {
              warning = "参数信息不全";
            }
          });
          if (warning) {
            this.$notify({
              type: "warning",
              message: "参数信息不全",
            });
            return;
          }
          this.loading = true;
          savePageAlg(params)
            .then((res) => {
              this.$notify({
                type: "success",
                message: "保存成功!",
                duration: 2500,
                offset: 57,
              });
              //this.id = res.data.id;
              this.copy_id = res.data.id;
              this.getPageDetail();
              this.loading = false;
            })
            .catch((e) => {
              console.log(e);
              if (e && e.status == 401) {
                return;
              }
              if (e && e.data == "算法名称不允许重复") {
                this.$notify({
                  type: "error",
                  message: "保存失败,算法名称不允许重复",
                  duration: 2500,
                  offset: 57,
                });
                this.loading = false;
                return;
              }
              this.$notify({
                type: "error",
                message: "保存失败,请稍后重试!",
                duration: 2500,
                offset: 57,
              });
              this.loading = false;
            });
        } else {
          return false;
        }
      });
    },
    saveRowVersion(row) {
      this.isVersionEdit = false;
      let params = {
        component_name: this.curEditRow.component_name,
        component_path: this.curEditRow.component_path,
        content: this.editData.content,
        id: this.editData.id,
        sdkId: this.copy_id,
        create_by: this.editData.create_by,
        create_time: this.editData.create_time,
        update_by: this.editData.update_by,
        update_time: this.editData.update_time,
        version: this.editData.version,
      };
      savePageAlgVersion(params)
        .then((res) => {
          if (res.code == 200) {
            this.$notify({
              type: "success",
              message: "保存成功!",
              position: "bottom-right",
              duration: 2500,
            });
            this.getPageDetail();
          }
        })
        .catch((e) => {
          this.$notify({
            type: "error",
            message: e.data,
            position: "bottom-right",
            duration: 2500,
          });
          this.getPageDetail();
        });
    },
    edit(row, index) {
      this.isVersionEdit = true;
      this.curEditIndex = index;
      this.editData = JSON.parse(JSON.stringify(row));
    },
    onFileUpload(params) {
      this.curEditRow.component_name = params.filename;
      getFilePath(params).then((res) => {
        if (res.code == 200) {
          this.curEditRow.component_path = res.data;
        }
      });
    },
    onFileAdded() {},
  },
};
</script>
<style lang="scss">
.pageAlg {
  height: 100%;
  .el-switch.is-checked .el-switch__core {
    border-color: #1a99ff;
    background-color: #1a99ff;
  }
  .orderTop {
    width: calc(100% - 60px);
    height: 30px;
    background: #fff;
    padding: 15px 30px;
    p {
      font-family: "PingFangSC-Regular";
      text-align: left;
      font-size: 14px;
      line-height: 30px;
    }
  }
  .orderBody {
    width: calc(100% - 40px);
    //height: calc(100% - 100px);
    padding: 20px;
    background: #f0f2f5;
  }
}
.info-block {
  background: #fff;
  padding: 20px;
  .info-header {
    border-bottom: 1px solid #eee;
    display: flex;
    padding: 10px 5px;
    margin-bottom: 10px;
    .title {
      font-size: 15px;
      font-weight: bold;
      margin-right: 16px;
    }
  }
  .info-body {
    display: flex;
    width: 100%;
    margin-bottom: 20px;
    .left,
    .right {
      width: 50%;
      text-align: left;
      .el-select {
        width: 100%;
      }
      .el-upload {
        width: 100px;
        height: 100px;
        line-height: 100px;
      }
    }
    .el-table {
      overflow: hidden;
    }
    .el-table th {
      background: rgb(248, 248, 248);
      color: rgb(34, 34, 34);
    }
    .operation {
      font-size: 20px;
      cursor: pointer;
      .el-icon-top {
        color: #409eff;
        margin-right: 10px;
      }
      .el-icon-remove-outline {
        color: red;
      }
      .el-icon-edit {
        margin-right: 10px;
      }
    }
  }
  .form-end {
    padding-top: 20px;
  }
}
.toAdd {
  font-size: 13px;
  color: #1a99ff !important;
  &:hover {
    color: #45abfc !important;
  }
  &:focus {
    color: #1789e5 !important;
  }
  cursor: pointer;
  i {
    font-size: 15px;
    margin-right: 2px;
  }
}
.avatar-uploader {
  float: left;
}
.second-icon-desc {
  float: left;
  margin-left: 50px;
}
.avatar-uploader .el-upload {
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
}
.avatar-uploader .el-upload-dragger {
  width: 100px;
  height: 100px;
}
.avatar-uploader .el-upload:hover {
  border-color: #409eff;
}
.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
}
.avatar {
  width: 178px;
  height: 178px;
  display: block;
}
</style>
src/views/AppManage/AppEdit.vue
New file
@@ -0,0 +1,646 @@
<template>
  <div class="pageAlg right-main">
    <div class="bread-crumb">
      <span class="prev-title">
        <router-link to="/layout/AppManage">应用列表</router-link>
      </span>
      <span class="devide"></span>
      <span class="cur-title"
        >{{ appId == "create" ? "创建" : "编辑" }}应用</span
      >
    </div>
    <div style="min-height: calc(100vh - 150px); background: #fff">
      <el-form
        :model="appForm"
        ref="appForm"
        :rules="rules"
        label-width="120px"
        v-loading="formLoading"
      >
        <div class="base-info info-block">
          <div class="info-header">
            <span class="title">基本信息</span>
          </div>
          <div class="info-body">
            <div class="left">
              <el-form-item label="应用名称" prop="name">
                <el-input v-model="appForm.name" size="small"></el-input>
              </el-form-item>
              <el-form-item label="应用包名" prop="package">
                <el-input v-model="appForm.package" size="small"></el-input>
              </el-form-item>
              <el-form-item label="加载方式" prop="type">
                <el-select v-model="appForm.type" size="small">
                  <el-option value="1" label="单独页面">单独页面</el-option>
                  <el-option value="2" label="弹窗">弹窗</el-option>
                </el-select>
              </el-form-item>
              <el-form-item label="应用路径" prop="url">
                <el-input v-model="appForm.url" size="small"></el-input>
              </el-form-item>
              <el-form-item label="应用标题" prop="title">
                <el-input v-model="appForm.title" size="small"></el-input>
              </el-form-item>
              <el-form-item label="应用类型" prop="isDefault">
                <el-radio v-model="appForm.isDefault" :label="true"
                  >默认应用</el-radio
                >
                <el-radio v-model="appForm.isDefault" :label="false"
                  >可选应用</el-radio
                >
              </el-form-item>
            </div>
            <div class="right">
              <el-form-item
                label="应用logo"
                prop="iconBlob"
                style="margin-bottom: 16px"
              >
                <el-upload
                  class="avatar-uploader"
                  drag
                  action="https://jsonplaceholder.typicode.com/posts/"
                  :show-file-list="false"
                  :http-request="uploadAlgLogo"
                  :on-success="onSuccess"
                  :before-upload="beforeUpload"
                >
                  <el-image
                    v-if="appForm.iconBlob"
                    :src="
                      appForm.iconBlob.indexOf(',') > 0
                        ? appForm.iconBlob
                        : `data:image/png;base64,${appForm.iconBlob}`
                    "
                    style="width: 100%; height: 100%"
                    fit="contain"
                  ></el-image>
                  <i v-else class="el-icon-plus avatar-uploader-icon"></i>
                  <div class="el-upload__text">
                    将图片拖到此处,或
                    <em>点击上传</em>
                  </div>
                </el-upload>
                <span class="second-icon-desc">其它风格应用logo:</span>
                <el-upload
                  class="avatar-uploader"
                  drag
                  action="https://jsonplaceholder.typicode.com/posts/"
                  :show-file-list="false"
                  :http-request="uploadAlgLogo2"
                  :on-success="onSuccess"
                  :before-upload="beforeUpload"
                >
                  <el-image
                    v-if="appForm.iconBlob2"
                    :src="
                      appForm.iconBlob2.indexOf(',') > 0
                        ? appForm.iconBlob2
                        : `data:image/png;base64,${appForm.iconBlob2}`
                    "
                    style="width: 100%; height: 100%"
                    fit="contain"
                  ></el-image>
                  <i v-else class="el-icon-plus avatar-uploader-icon"></i>
                  <div class="el-upload__text">
                    将图片拖到此处,或
                    <em>点击上传</em>
                  </div>
                </el-upload>
              </el-form-item>
              <el-form-item
                label="默认宽"
                prop="width"
                v-if="appForm.type == '2'"
              >
                <el-input v-model.number="appForm.width" size="small">
                  <template slot="append">px</template>
                </el-input>
              </el-form-item>
              <el-form-item
                label="默认高"
                prop="height"
                v-if="appForm.type == '2'"
              >
                <el-input v-model.number="appForm.height" size="small">
                  <template slot="append">px</template>
                </el-input>
              </el-form-item>
            </div>
          </div>
          <div class="form-end">
            <el-button size="small" @click="goBack">取消</el-button>
            <el-button type="primary" size="small" @click="saveForm"
              >保存</el-button
            >
          </div>
        </div>
      </el-form>
      <div class="base-info info-block">
        <div class="info-header">
          <span class="title">应用版本</span>
          <div class="toAdd" @click="toAddVersion">
            <i class="el-icon-circle-plus-outline"></i>
            <span>添加</span>
          </div>
        </div>
        <div class="info-body">
          <el-table :data="versionInfo" style="width: 100%" border>
            <el-table-column
              type="index"
              width="50"
              label="序号"
              align="center"
            ></el-table-column>
            <el-table-column
              prop="version_show"
              width="260"
              label="版本号"
              align="center"
            >
              <template slot-scope="scope">
                <div>
                  <span>{{ scope.row.version_show }}</span>
                </div>
              </template>
            </el-table-column>
            <el-table-column
              prop="content"
              width="500"
              label="版本更新内容"
              header-align="center"
            >
              <template slot-scope="scope">
                <div v-if="isVersionEdit && scope.$index == curEditIndex">
                  <el-input v-model="editData.content" size="mini"></el-input>
                </div>
                <div v-else>
                  <span>{{ scope.row.content }}</span>
                </div>
              </template>
            </el-table-column>
            <el-table-column
              prop="updateTime"
              width="290"
              label="更新时间"
              align="center"
            ></el-table-column>
            <el-table-column
              prop="updateUserName"
              width="150"
              label="更新人"
              align="center"
            ></el-table-column>
            <el-table-column width="250" label="附件" align="center">
              <template slot-scope="scope">
                <div
                  v-if="
                    isVersionEdit &&
                    scope.$index == curEditIndex &&
                    !scope.row.id
                  "
                >
                  <file-uploader
                    single
                    uploadPlaceholder="上传应用文件"
                    url="/data/api-f/file/upload"
                    @complete="onFileUpload"
                    @file-added="onFileAdded"
                  />
                </div>
                <div v-else>{{ scope.row.component_name }}</div>
              </template>
            </el-table-column>
            <el-table-column label="操作" align="center" width="100">
              <template slot-scope="scope">
                <div v-if="isVersionEdit && scope.$index == curEditIndex">
                  <span class="cursor-pointer" @click="cancel(scope)"
                    >取消</span
                  >
                  <span
                    class="cursor-pointer"
                    @click="saveRowVersion(scope.row)"
                    >保存</span
                  >
                </div>
                <div class="operation" v-else>
                  <i class="el-icon-edit" @click="editAppVersion(scope)"></i>
                  <i
                    class="el-icon-remove-outline"
                    @click="removeAppVersion(scope)"
                  ></i>
                </div>
              </template>
            </el-table-column>
          </el-table>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
// import {
//   saveApp,
//   showAppDetail,
//   saveAppVersion,
//   deleteAppVersion,
// } from "@/api/app";
import { getFilePath } from "@/api/utils";
import FileUploader from "@/components/subComponents/FileUpload/index";
export default {
  components: {
    FileUploader,
  },
  props: ["appId"],
  data() {
    return {
      appForm: {
        name: "",
        package: "",
        type: "",
        url: "",
        title: "",
        iconBlob: "",
        iconBlob2: "",
        isDefault: false,
      },
      rules: {
        name: [
          { required: true, message: "请输入应用名称", trigger: "blur" },
          { min: 1, max: 15, message: "长度在1到15个字符", trigger: "blur" },
        ],
        iconBlob: [
          { required: true, message: "请上传应用logo", trigger: "blur" },
        ],
        package: [
          { required: true, message: "请输入应用包名", trigger: "blur" },
          { min: 1, max: 50, message: "长度在1到50个字符", trigger: "blur" },
        ],
        type: [
          { required: true, message: "请选择应用加载方式", trigger: "change" },
        ],
        title: [
          { required: true, message: "请输入应用标题", trigger: "blur" },
          { min: 1, max: 15, message: "长度在1到15个字符", trigger: "blur" },
        ],
        width: [
          { required: true, message: "请输入应用默认宽", trigger: "blur" },
          {
            type: "number",
            message: "请输入100到1920之间的整数",
            trigger: "blur",
          },
          // { min: 100, message: '默认宽不能小于100', trigger: 'blur' },
          // { max: 1920, message: '默认宽不能大于1920', trigger: 'blur' }
        ],
        height: [
          { required: true, message: "请输入应用默认高", trigger: "blur" },
          {
            type: "number",
            message: "请输入100到1200之间的整数",
            trigger: "blur",
          },
        ],
      },
      versionInfo: [],
      editData: {},
      isVersionEdit: false,
      curEditIndex: 0,
      curEditRow: {},
      formLoading: false,
      // lastComponent_name:'',
      // lastComponent_path:''
    };
  },
  mounted() {
    if (this.appId != "create") {
      this.showDetail();
    }
  },
  methods: {
    newAppVersion() {
      return {
        version: "",
        content: "",
        updateTime: "",
        person: "",
        component_name: "",
        component_path: "",
      };
    },
    toAddVersion() {
      if (this.isVersionEdit) return;
      this.editData = this.newAppVersion();
      this.versionInfo.push(this.editData);
      this.isVersionEdit = true;
      this.curEditIndex = this.versionInfo.length - 1;
    },
    beforeUpload() {},
    uploadAlgLogo(params) {
      let file = params.file;
      let fileReader = new FileReader();
      if (file) {
        fileReader.readAsDataURL(file);
      }
      fileReader.onload = () => {
        this.appForm.iconBlob = fileReader.result.substring(
          fileReader.result.indexOf(",") + 1
        );
      };
    },
    uploadAlgLogo2(params) {
      let file = params.file;
      let fileReader = new FileReader();
      if (file) {
        fileReader.readAsDataURL(file);
      }
      fileReader.onload = () => {
        this.appForm.iconBlob2 = fileReader.result.substring(
          fileReader.result.indexOf(",") + 1
        );
      };
    },
    onSuccess() {},
    saveForm() {
      this.$refs["appForm"].validate((valid) => {
        if (valid) {
          this.formLoading = true;
          let params = {
            iconBlob: this.appForm.iconBlob,
            iconBlob2: this.appForm.iconBlob2,
            id: this.appForm.id,
            name: this.appForm.name,
            package: this.appForm.package,
            title: this.appForm.title,
            type: this.appForm.type,
            url: this.appForm.url,
            width: this.appForm.width,
            height: this.appForm.height,
            isDefault: this.appForm.isDefault,
          };
          saveApp(params)
            .then((res) => {
              if (res.code == 200) {
                this.$notify({
                  type: "success",
                  message: "保存成功!",
                  duration: 2500,
                  offset: 57,
                });
                this.formLoading = false;
                this.appId = res.data.id;
                this.showDetail();
              }
            })
            .catch((e) => {
              if (e && e.status == 401) {
                return;
              }
              this.$notify({
                type: "error",
                message: "保存失败,请稍后重试!",
                duration: 2500,
                offset: 57,
              });
              console.log(e);
              this.formLoading = false;
            });
        } else {
          return false;
        }
      });
    },
    showDetail() {
      showAppDetail({ id: this.appId })
        .then((res) => {
          if (res.code == 200) {
            this.appForm = res.data.appInfo;
            this.versionInfo = res.data.versions;
          }
        })
        .catch((e) => {
          console.log(e);
        });
    },
    goBack() {
      this.$router.go(-1);
    },
    removeAppVersion(scope) {
      this.$confirm("确定删除该项吗?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
        center: true,
      })
        .then(() => {
          deleteAppVersion({ id: scope.row.id }).then((res) => {
            if (res.code == 200) {
              this.$message({
                type: "success",
                message: "删除成功!",
              });
              this.showDetail();
            }
          });
        })
        .catch((e) => {
          console.log(e);
        });
    },
    // rowClick (row, column, ev) {
    //   this.curEditRow = JSON.parse(JSON.stringify(row));
    // },
    saveRowVersion(row) {
      let params = {
        app_id: this.appId,
        component_name: row.id
          ? row.component_name
          : this.curEditRow.component_name,
        component_path: row.id
          ? row.component_path
          : this.curEditRow.component_path,
        content: this.editData.content,
        id: this.editData.id,
        updateBy: this.editData.updateBy,
        updateTime: this.editData.updateTime,
        updateUserName: this.editData.updateUserName,
        version: this.editData.version,
      };
      saveAppVersion(params)
        .then((res) => {
          if (res.code == 200) {
            this.$notify({
              type: "success",
              message: "保存成功!",
              position: "bottom-right",
              duration: 2500,
            });
            this.isVersionEdit = false;
            this.showDetail();
          }
        })
        .catch((e) => {
          if (e && e.status == 401) {
            return;
          }
          this.$notify({
            type: "error",
            message: e.data,
            position: "bottom-right",
            duration: 2500,
          });
        });
    },
    cancel(scope) {
      this.isVersionEdit = false;
      if (!scope.row.id) {
        this.versionInfo.splice(this.versionInfo.length - 1, 1);
      }
    },
    editAppVersion(scope) {
      this.isVersionEdit = true;
      this.curEditIndex = scope.$index;
      this.editData = JSON.parse(JSON.stringify(scope.row));
    },
    onFileUpload(params) {
      this.curEditRow.component_name = params.filename;
      getFilePath(params).then((res) => {
        if (res.code == 200) {
          this.curEditRow.component_path = res.data;
        }
      });
    },
    onFileAdded() {},
  },
};
</script>
<style lang="scss">
.pageAlg {
  height: 100%;
  .orderTop {
    width: calc(100% - 60px);
    height: 30px;
    background: #fff;
    padding: 15px 30px;
    p {
      font-family: "PingFangSC-Regular";
      text-align: left;
      font-size: 14px;
      line-height: 30px;
    }
  }
  .orderBody {
    width: calc(100% - 40px);
    //height: calc(100% - 100px);
    padding: 20px;
    background: #f0f2f5;
  }
}
.info-block {
  background: #fff;
  padding: 20px;
  .info-header {
    border-bottom: 1px solid #eee;
    display: flex;
    padding: 10px 5px;
    margin-bottom: 10px;
    .title {
      font-size: 15px;
      font-weight: bold;
      margin-right: 16px;
    }
  }
  .info-body {
    display: flex;
    width: 100%;
    margin-bottom: 20px;
    .left,
    .right {
      width: 50%;
      text-align: left;
      .el-input-group__append {
        color: #999;
      }
      .el-select {
        width: 100%;
      }
      .el-upload {
        width: 100px;
        height: 100px;
        line-height: 100px;
      }
      .des {
        position: absolute;
        top: 110px;
        left: 175px;
        font-size: 12px;
      }
    }
    .el-table {
      overflow: hidden;
    }
    .el-table th {
      background: rgb(248, 248, 248);
      color: rgb(34, 34, 34);
    }
    .operation {
      font-size: 20px;
      cursor: pointer;
      .el-icon-top {
        color: #409eff;
        margin-right: 10px;
      }
      .el-icon-remove-outline {
        color: red;
      }
      .el-icon-edit {
        margin-right: 10px;
      }
    }
  }
  .form-end {
    padding-top: 20px;
  }
}
.toAdd {
  font-size: 13px;
  color: #3d68e1;
  cursor: pointer;
  i {
    font-size: 15px;
    margin-right: 2px;
  }
}
.avatar-uploader {
  float: left;
}
.second-icon-desc {
  float: left;
  margin-left: 50px;
}
.avatar-uploader .el-upload {
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
}
.avatar-uploader .el-upload-dragger {
  width: 100px;
  height: 100px;
}
.avatar-uploader .el-upload:hover {
  border-color: #409eff;
}
.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
}
.avatar {
  width: 178px;
  height: 178px;
  display: block;
}
</style>
src/views/AppManage/AppManage.vue
New file
@@ -0,0 +1,170 @@
<template>
  <div class="right-main">
    <div class="top-title">
      <p>应用列表</p>
    </div>
    <div class="control-bar">
      <div class="line-one">
        <div class="screening">
          <label>应用名称</label>
          <el-input v-model="inputText" placeholder="请输入" prefix-icon="el-icon-search" size="small"></el-input>
        </div>
        <div class="screening">
          <el-button plain class="btn-search" type="primary" size="small" @click="renderAppList(1)">搜索</el-button>
          <el-button class="btn-reset" @click="clearSearch" size="small">重置</el-button>
        </div>
      </div>
      <div class="right-fixed">
        <el-button class="cursor-pointer" type="primary" @click="addApp" size="small">创建应用</el-button>
      </div>
    </div>
    <div class="table-area" ref="container">
      <el-table
        tooltip-effect="dark"
        :data="dataList"
        :fit="true"
        :default-sort="{ prop: 'createTime', order: 'descending' }"
      >
        <!-- <el-table-column type="selection" width="30"></el-table-column> -->
        <el-table-column label="序号" width="68">
          <template slot-scope="scope">{{ scope.$index + 1 + (page - 1) * size }}</template>
        </el-table-column>
        <el-table-column prop="id" label="应用编号" sortable width="220"></el-table-column>
        <el-table-column prop="isDefault" label="应用类型" width="150">
          <template slot-scope="scope">
            <div>{{ scope.row.isDefault ? "默认应用" : "可选应用" }}</div>
          </template>
        </el-table-column>
        <el-table-column prop="name" label="应用名称" sortable min-width="200"></el-table-column>
        <el-table-column prop="version" label="最新版本号" width="150" sortable></el-table-column>
        <el-table-column
          prop="updateTime"
          label="最后更新时间"
          width="240"
          show-overflow-tooltip
          sortable
        ></el-table-column>
        <el-table-column prop="updateUserName" label="更新人" width="130" sortable></el-table-column>
        <el-table-column label="操作" width="120">
          <template slot-scope="scope">
            <span class="cursor-pointer" @click="editRow(scope.row.id)">编辑</span>
            <span class="cursor-pointer" @click="deleteRow(scope.row.id)">删除</span>
          </template>
        </el-table-column>
      </el-table>
      <div>
        <el-pagination
          @current-change="refrash"
          @size-change="handleSizeChange"
          :current-page="page"
          :page-size="size"
          :page-sizes="[5, 10, 15, 20, 25]"
          layout="total, sizes, prev, pager, next, jumper"
          :total="total"
        ></el-pagination>
      </div>
    </div>
  </div>
</template>
<script>
// import { getAppList, deleteApp } from "@/api/app"
export default {
  data() {
    return {
      inputText: "",
      page: 1,
      size: 10,
      total: 0,
      dataList: [],
      tableHeight: window.innerHeight - 400,
      tableLoading: false
    }
  },
  mounted() {
    this.renderAppList()
  },
  methods: {
    renderAppList(v) {
      this.tableLoading = true
      let params = {
        inputText: this.inputText,
        page: v === 1 ? 1 : this.page,
        size: this.size
      }
      // getAppList(params)
      //   .then((res) => {
      //     if (res.code) {
      //       this.dataList = res.data.list
      //       this.total = res.data.total
      //       this.tableLoading = false
      //       if (res.data.total <= this.size) {
      //         this.page = 1
      //       }
      //     }
      //   })
      //   .catch((e) => {
      //     console.log(e)
      //     this.tableLoading = false
      //     if (e && e.status == 401) {
      //       return
      //     }
      //     this.$notify({
      //       type: "error",
      //       message: "数据获取失败,请稍后重试!",
      //       duration: 2500,
      //       offset: 57
      //     })
      //   })
    },
    refrash(page) {
      this.page = page
      this.renderAppList()
    },
    clearSearch() {
      this.inputText = ""
      this.renderAppList()
    },
    handleSizeChange(size) {
      this.size = size
      this.renderAppList()
    },
    addApp() {
      this.$router.push({ name: "appEdit", params: { appId: "create" } })
    },
    editRow(id) {
      this.$router.push({ name: "appEdit", params: { appId: id } })
    },
    deleteRow(id) {
      this.$confirm("确定删除该应用吗?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
        center: true
      })
        .then(() => {
          // deleteApp({ id }).then((res) => {
          //   if (res.code == 200) {
          //     this.$message({
          //       type: "success",
          //       message: "删除成功!"
          //     })
          //     this.renderAppList()
          //   }
          // })
        })
        .catch((e) => {
          console.log(e)
        })
    }
  }
}
</script>
<style lang="scss">
// .el-message-box__status.el-icon-warning {
//     left: 75px;
//     font-size: 20px !important;
// }
</style>