YY 2 anni fa
parent
commit
1410095c76

File diff suppressed because it is too large
+ 626 - 207
package-lock.json


+ 1 - 0
package.json

@@ -12,6 +12,7 @@
     "format": "prettier --write src/"
   },
   "dependencies": {
+    "lodash": "^4.17.21",
     "pinia": "^2.0.32",
     "vue": "^3.2.47",
     "vue-router": "^4.1.6"

+ 14 - 0
src/components/frame/btn-1.vue

@@ -0,0 +1,14 @@
+<template>
+  <div id="btn">
+    <el-button type="success" @click="toAdd()">新增</el-button>
+    <el-button type="primary" disabled>修改</el-button>
+    <el-button type="danger" disabled>删除</el-button>
+    <el-button type="warning" disabled>导出</el-button>
+  </div>
+</template>
+<script setup lang="ts">
+const emit = defineEmits(['toAdd']);
+const toAdd = () => {
+  emit('toAdd');
+};
+</script>

+ 220 - 0
src/components/frame/c-form.vue

@@ -0,0 +1,220 @@
+<template>
+  <div id="c-form">
+    <el-row type="flex" justify="space-around">
+      <el-col :span="span">
+        <el-form ref="formRef" :model="form" :rules="rules" :label-width="labelWidth" class="form" @submit.prevent>
+          <template v-for="(item, index) in fields">
+            <el-form-item v-if="display(item)" :key="'form-field-' + index" :label="getField('label', item)" :prop="item.model" :required="item.required">
+              <template v-if="!item.custom">
+                <template v-if="item.type === 'textarea'">
+                  <el-input
+                    clearable
+                    v-model="form[item.model]"
+                    :type="item.type"
+                    :placeholder="getField('placeholder', item)"
+                    v-bind="item.options"
+                    @change="dataChange(item.model)"
+                    show-word-limit
+                    :disabled="item.readonly"
+                  ></el-input>
+                </template>
+                <template v-else-if="item.type === 'numbers'">
+                  <el-input-number
+                    v-model="form[item.model]"
+                    :placeholder="getField('placeholder', item)"
+                    @change="dataChange(item.model)"
+                    style="width: 100%"
+                    :disabled="item.readonly"
+                  />
+                </template>
+                <template v-else-if="item.type === 'radio'">
+                  <el-radio-group v-model="form[item.model]" :type="item.type" v-bind="item.options" @change="dataChange(item.model)" :disabled="item.readonly">
+                    <slot :name="item.model" v-bind="{ item }"></slot>
+                  </el-radio-group>
+                </template>
+                <template v-else-if="item.type === 'checkbox'">
+                  <el-checkbox-group v-model="form[item.model]" :type="item.type" v-bind="item.options" :disabled="item.readonly">
+                    <slot :name="item.model" v-bind="{ item }"></slot>
+                  </el-checkbox-group>
+                </template>
+                <template v-else-if="item.type === 'select'">
+                  <el-select
+                    clearable
+                    filterable
+                    v-model="form[item.model]"
+                    :type="item.type"
+                    :placeholder="getField('selectplaceholder', item)"
+                    v-bind="item.options"
+                    @change="dataChange(item.model)"
+                    style="width: 100%"
+                    :disabled="item.readonly"
+                  >
+                    <slot :name="item.model" v-bind="{ item }"></slot>
+                  </el-select>
+                </template>
+                <template v-else-if="item.type === 'selectMany'">
+                  <el-select
+                    filterable
+                    clearable
+                    multiple
+                    collapse-tags
+                    v-model="form[item.model]"
+                    :type="item.type"
+                    :placeholder="getField('selectplaceholder', item)"
+                    v-bind="item.options"
+                    @change="dataChange(item.model)"
+                    style="width: 100%"
+                    :disabled="item.readonly"
+                  >
+                    <slot :name="item.model" v-bind="{ item }"></slot>
+                  </el-select>
+                </template>
+                <template
+                  v-else-if="
+                    item.type === `year` ||
+                    item.type == 'month' ||
+                    item.type == 'date' ||
+                    item.type == 'daterange' ||
+                    item.type == 'datetime' ||
+                    item.type == 'datetimerange'
+                  "
+                >
+                  <el-date-picker
+                    v-model="form[item.model]"
+                    :type="item.type"
+                    :placeholder="getField('selectplaceholder', item)"
+                    :format="getDateFormat(item.type)"
+                    :value-format="getDateFormat(item.type)"
+                    v-bind="item.options"
+                    @change="dataChange(item.model)"
+                    range-separator="至"
+                    style="width: 100%"
+                    :disabled="item.readonly"
+                  >
+                  </el-date-picker>
+                </template>
+                <template v-else-if="item.type === `time`">
+                  <el-time-picker
+                    v-model="form[item.model]"
+                    :placeholder="getField('selectplaceholder', item)"
+                    :format="getDateFormat(item.type)"
+                    :value-format="getDateFormat(item.type)"
+                    v-bind="item.options"
+                    @change="dataChange(item.model)"
+                    style="width: 100%"
+                    :disabled="item.readonly"
+                  >
+                  </el-time-picker>
+                </template>
+                <template v-else>
+                  <el-input
+                    clearable
+                    v-model="form[item.model]"
+                    :type="getField('type', item)"
+                    :placeholder="getField('placeholder', item)"
+                    :show-password="getField('type', item) === 'password'"
+                    v-bind="item.options"
+                    @change="dataChange(item.model)"
+                    :disabled="item.readonly"
+                  ></el-input>
+                </template>
+              </template>
+              <template v-else>
+                <slot :name="item.model" v-bind="{ item }"></slot>
+              </template>
+            </el-form-item>
+          </template>
+          <el-col :span="24" label="" class="btn" v-if="isSave">
+            <slot name="submit">
+              <el-button type="primary" @click="save(formRef)">{{ submitText }}</el-button>
+            </slot>
+          </el-col>
+        </el-form>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, toRefs } from 'vue';
+import type { FormInstance } from 'element-plus';
+import _ from 'lodash';
+// #region 传递
+interface fieldsItem {
+  model: string;
+  type: string;
+  readonly: string;
+  options: object;
+  custom: string;
+  required: string;
+  limit: number | undefined;
+  url: string;
+}
+const props = defineProps({
+  fields: { type: Array<fieldsItem>, default: () => [{ readonly: false }] },
+  rules: { type: Object, default: () => {} },
+  labelWidth: { type: String, default: '120px' },
+  submitText: { type: String, default: '保存' },
+  form: { type: Object, default: () => {} },
+  reset: { type: Boolean, default: false },
+  isSave: { type: Boolean, default: true },
+  span: { type: Number, default: 24 }, // 限制两侧的距离,24就是整行全用
+});
+const { fields } = toRefs(props);
+const { rules } = toRefs(props);
+const { labelWidth } = toRefs(props);
+const { submitText } = toRefs(props);
+const { form } = toRefs(props);
+const { reset } = toRefs(props);
+const { isSave } = toRefs(props);
+const { span } = toRefs(props);
+const formRef = ref<FormInstance>();
+const getField = (item: string, data: any) => {
+  let res: string | null | boolean = _.get(data, item, null);
+  if (item === 'type') res = res === null ? `text` : res;
+  if (item === 'placeholder') res = res === null ? `请输入${data.label}` : res;
+  if (item === `selectplaceholder`) res = res === null ? `请选择${data.label}` : res;
+  if (item === 'required') res = res === null ? false : res;
+  if (item === `error`) res = res === null ? `${data.label}错误` : res;
+  return res;
+};
+
+const getDateFormat = (e: string) => {
+  if (e === 'year') return 'YYYY';
+  if (e === 'month') return 'MM';
+  if (e === 'date') return 'YYYY-MM-DD';
+  if (e === 'daterange') return 'YYYY-MM-DD';
+  if (e === 'datetime') return 'YYYY-MM-DD HH:mm:ss';
+  if (e === 'datetimerange') return 'YYYY-MM-DD HH:mm:ss';
+  if (e === 'time') return 'HH:mm:ss';
+};
+const emit = defineEmits(['save', 'dataChange']);
+const clear = ref<any>();
+// 提交
+const save = async (formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  await formEl.validate((valid, fields) => {
+    if (valid) {
+      emit('save', form.value);
+      if (reset.value) clear.value.resetFields();
+    } else {
+      console.log('error submit!', fields);
+    }
+  });
+};
+const display = (field: any) => {
+  let dis = _.get(field, `display`);
+  if (!_.isFunction(dis)) return true;
+  else return dis(field, form);
+};
+const dataChange = (model: string) => {
+  const value = form.value[model];
+  emit('dataChange', { model, value });
+};
+</script>
+
+<style scoped>
+.btn {
+  text-align: center;
+}
+</style>

+ 332 - 0
src/components/frame/c-table.vue

@@ -0,0 +1,332 @@
+<template>
+  <div id="c-table">
+    <el-table
+      ref="table"
+      :row-key="rowKey"
+      :data="data"
+      border
+      stripe
+      :max-height="height !== null ? height : ''"
+      @select="handleSelectionChange"
+      @select-all="handleSelectAll"
+      :show-summary="useSum"
+      @row-click="rowClick"
+      :summary-method="computedSum"
+    >
+      <el-table-column type="selection" width="55" v-if="select" :prop="rowKey" :reserve-selection="true"> </el-table-column>
+      <template v-for="(item, index) in fields">
+        <template v-if="item.custom">
+          <el-table-column :key="index" align="center" :label="item.label" v-bind="item.options" :show-overflow-tooltip="item.showTip || true">
+            <template v-slot="{ row }">
+              <slot :name="item.model" v-bind="{ item, row }"></slot>
+            </template>
+          </el-table-column>
+        </template>
+        <template v-else>
+          <el-table-column
+            :key="index"
+            align="center"
+            :label="item.label"
+            :prop="item.model"
+            :formatter="toFormatter"
+            :sortable="true"
+            v-bind="item.options"
+            :show-overflow-tooltip="item.showTip === false ? item.showTip : true"
+          >
+          </el-table-column>
+        </template>
+      </template>
+      <template v-if="opera.length > 0">
+        <el-table-column label="操作" align="center" :width="operaWidth">
+          <template v-slot="{ row, $index }">
+            <template v-for="(item, index) in opera">
+              <template v-if="display(item, row)">
+                <template v-if="vOpera">
+                  <el-link
+                    v-opera="item.method"
+                    :key="`${item.model}-column-${index}`"
+                    :type="item.type || 'primary'"
+                    :icon="item.icon || ''"
+                    size="small"
+                    style="padding-right: 10px"
+                    :underline="false"
+                    @click="handleOpera(row, item.method, item.confirm, item.methodZh, item.label, $index, item.confirmWord)"
+                  >
+                    {{ item.label }}
+                  </el-link>
+                </template>
+                <template v-else>
+                  <el-link
+                    :key="`${item.model}-column-${index}`"
+                    :type="item.type || 'primary'"
+                    :icon="item.icon || ''"
+                    size="small"
+                    style="padding-right: 10px"
+                    :underline="false"
+                    @click="handleOpera(row, item.method, item.confirm, item.methodZh, item.label, $index, item.confirmWord)"
+                  >
+                    {{ item.label }}
+                  </el-link>
+                </template>
+              </template>
+            </template>
+          </template>
+        </el-table-column>
+      </template>
+    </el-table>
+    <el-row type="flex" align="middle" justify="end" v-if="usePage">
+      <el-col :span="24" class="page">
+        <el-pagination
+          background
+          layout="sizes,total, prev, pager, next"
+          :page-sizes="[10, 20, 50, 100, 200]"
+          :total="total"
+          :page-size="limit"
+          v-model:current-page="currentPage"
+          @current-change="changePage"
+          @size-change="sizeChange"
+        >
+        </el-pagination>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+<script setup lang="ts">
+import type { Ref } from 'vue';
+import { ref, toRefs, nextTick, getCurrentInstance } from 'vue';
+import { ElMessageBox } from 'element-plus';
+
+import _ from 'lodash';
+const { proxy } = getCurrentInstance() as any;
+
+// #region 传递
+
+interface fieldsItem {
+  custom: string;
+  label: string;
+  options: string;
+  showTip: boolean;
+  model: string;
+}
+interface operaItem {
+  method: string;
+  model: string;
+  type: string;
+  icon: string;
+  confirmWord: string;
+  label: string;
+  confirm: boolean;
+  methodZh: string;
+}
+interface dataItem {
+  _id?: string;
+}
+
+const props = defineProps({
+  fields: { type: Array<fieldsItem>, required: true },
+  data: { type: Array<dataItem>, required: true },
+  opera: { type: Array<operaItem>, default: () => [] },
+  rowKey: { type: String, default: '_id' },
+  select: { type: Boolean, default: false },
+  selected: { type: Array, default: () => [] },
+  usePage: { type: Boolean, default: true },
+  total: { type: Number, default: 0 },
+  useSum: { type: Boolean, default: false },
+  sumcol: { type: Array, default: () => [] },
+  sumres: { type: String, default: 'total' },
+  // limit: { type: Number, default: 10 },
+  height: null,
+  operaWidth: { type: Number, default: 200 },
+  vOpera: { type: Boolean, default: false },
+});
+const { fields } = toRefs(props);
+const { data } = toRefs(props);
+const { opera } = toRefs(props);
+const { rowKey } = toRefs(props);
+const { select } = toRefs(props);
+const { selected } = toRefs(props);
+const { usePage } = toRefs(props);
+const { total } = toRefs(props);
+const { useSum } = toRefs(props);
+const { sumcol } = toRefs(props);
+const { sumres } = toRefs(props);
+// const { limit } = toRefs(props);
+const { height } = toRefs(props);
+const { operaWidth } = toRefs(props);
+const { vOpera } = toRefs(props);
+// #endregion
+const emit = defineEmits(['method', 'handleSelect', 'query', 'rowClick']);
+
+let pageSelected: Ref<any[]> = ref([]);
+let currentPage: Ref<number> = ref(1);
+
+let limit: number = proxy.$limit;
+const toFormatter = (row: any, column: { property: string }, cellValue: string, index: string) => {
+  let this_fields = fields.value.filter((fil) => fil.model === column.property);
+  if (this_fields.length > 0) {
+    let format: any = _.get(this_fields[0], `format`, false);
+    if (format) {
+      let res;
+      if (_.isFunction(format)) {
+        res = format(cellValue);
+      } else {
+        res = toFormat({
+          model: this_fields[0].model,
+          value: cellValue,
+        });
+      }
+      return res;
+    } else {
+      return cellValue;
+    }
+  }
+};
+const toFormat = (e: { model: string; value: string }) => {};
+const handleOpera = (data: string, method: any, confirm = false, methodZh: string, label: string, index: string, confirmWord: string) => {
+  let self = true;
+  if (_.isFunction(methodZh)) methodZh = methodZh(data);
+  else if (!_.isString(methodZh)) {
+    methodZh = label;
+    self = false;
+  }
+  if (confirm) {
+    let word = self ? methodZh : `您确认${methodZh}该数据?`;
+    if (confirmWord) word = confirmWord;
+    ElMessageBox.confirm(word, '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' })
+      .then(() => {
+        emit(method, data, index);
+      })
+      .catch(() => {});
+  } else emit(method, data, index);
+};
+const handleSelectionChange = (selection: string, row: never) => {
+  //根据row是否再pageSelected中,判断是添加还是删除
+  let isSelecteds = _.cloneDeep(pageSelected);
+  const is_has = isSelecteds.value.findIndex((f) => f[rowKey.value] === row[rowKey.value]);
+  if (is_has <= -1) {
+    // 没有找到,属于添加
+    isSelecteds.value.push(row);
+  } else {
+    // 找到了,删除
+    isSelecteds.value.splice(is_has, 1);
+  }
+  pageSelected.value = isSelecteds.value;
+  emit(`handleSelect`, isSelecteds);
+};
+const handleSelectAll = (selection: any) => {
+  //处于没全选状态,选择之后一定是全选,只有处于全选状态时,才会反选(全取消)
+  let res: any = [];
+  if (selection.length > 0) {
+    //全选
+    res = _.uniqBy(pageSelected.value.concat(selection), rowKey.value);
+  } else {
+    //全取消
+    res = _.differenceBy(pageSelected.value, data.value, rowKey.value);
+  }
+  pageSelected.value = res;
+  emit(`handleSelect`, res);
+};
+const table = ref<any>();
+const initSelection = () => {
+  nextTick(() => {
+    table.value.clearSelection();
+    selected.value.forEach((info: any) => {
+      let d = data.value.filter((p) => p._id === info._id);
+      if (d.length > 0) table.value.toggleRowSelection(d[0]);
+    });
+  });
+};
+const selectReset = () => {
+  table.value.clearSelection();
+};
+const changePage = (page: number = currentPage.value) => {
+  emit('query', { skip: (page - 1) * limit, limit: limit });
+};
+const sizeChange = (limits: number) => {
+  limit = limits;
+  currentPage.value = 1;
+  emit('query', { skip: 0, limit: limit });
+};
+const rowClick = (row: any, column: string, event: string) => {
+  emit(`rowClick`, row);
+};
+const display = (item: operaItem, row: any) => {
+  let display: any = _.get(item, `display`, true);
+  if (display === true) return true;
+  else {
+    let res = display(row);
+    return res;
+  }
+};
+// 计算合计
+const computedSum = (columns: any, data: any) => {
+  if (columns.length <= 0 || data.length <= 0) return '';
+  const result = [];
+  const reg = new RegExp(/^\d+$/);
+  for (const column of columns) {
+    // 判断有没有prop属性
+    const prop = _.get(column, 'property');
+    if (!prop) {
+      result.push('');
+      continue;
+    }
+    // 判断是否需要计算
+    const inlist = sumcol.value.find((f) => f == prop);
+    if (!inlist) {
+      result.push('');
+      continue;
+    }
+    let res: number | unknown = 0;
+    // 整理出要计算的属性(只取出数字或者可以为数字的值)
+    const resetList = data.map((i: any) => {
+      const d = _.get(i, prop);
+      return d * 1;
+    });
+    let p1: any;
+    if (sumres.value === 'total') {
+      res = totalComputed(p1, resetList);
+    } else if (sumres.value === 'avg') {
+      res = avgComputed(resetList);
+    } else if (sumres.value === 'max') {
+      res = maxComputed(resetList);
+    } else if (sumres.value === 'min') {
+      res = minComputed(resetList);
+    }
+    result.push(res);
+  }
+  result[0] = '合计';
+  return result;
+};
+// 合计计算
+const totalComputed = (columns: any, data: any) => {
+  const total = data.reduce((p: number, n: string) => p + parseFloat(n), 0);
+  return total;
+};
+// 平均值计算
+const avgComputed = (data: any) => {
+  let p1: any;
+  const total = totalComputed(p1, data);
+  return _.round(_.divide(total, data.length), 2);
+};
+// 最大值计算
+const maxComputed = (data: any) => {
+  return _.max(data);
+};
+// 最小值计算
+const minComputed = (data: any) => {
+  return _.min(data);
+};
+</script>
+
+<style scoped>
+.page {
+  background-color: #fff;
+  padding: 8px;
+  height: 50px;
+}
+.el-pagination {
+  position: absolute;
+  right: 10px;
+  background-color: #fff;
+}
+</style>

+ 103 - 0
src/components/frame/c-upload.vue

@@ -0,0 +1,103 @@
+<template>
+  <div id="c-upload">
+    <el-upload
+      v-if="url"
+      ref="upload"
+      :action="url"
+      :limit="limit"
+      :accept="accept"
+      :file-list="list"
+      :list-type="listType"
+      :on-exceed="outLimit"
+      :on-preview="filePreview"
+      :on-success="onSuccess"
+      :before-remove="onRemove"
+    >
+      <el-button type="primary">选择文件</el-button>
+      <template #tip v-if="tip">
+        <p style="color: #ff0000">{{ tip }}</p>
+      </template>
+    </el-upload>
+    <el-dialog v-model="dialog.show" append-to-body>
+      <img width="100%" :src="dialog.url" alt="" />
+    </el-dialog>
+  </div>
+</template>
+
+<script setup lang="ts">
+import type { Ref } from 'vue';
+import { ref, toRefs } from 'vue';
+import { ElMessage } from 'element-plus';
+import _ from 'lodash';
+
+// #region
+interface ListItem {
+  errcode?: string | number;
+  errmsg?: string;
+  uri?: string;
+  name?: string;
+  url?: string;
+  id?: any;
+}
+let dialog: Ref<{ show: boolean; url: string }> = ref({ show: false, url: '' });
+const props = defineProps({
+  url: { type: String, default: () => '' },
+  limit: { type: Number, default: () => 6 },
+  accept: { type: String, default: () => 'image/png, image/jpeg' },
+  listType: { type: String, default: () => 'text' },
+  tip: { type: String, default: () => undefined },
+  list: { type: Array<ListItem>, default: () => [] },
+  model: { type: String, default: () => '' },
+});
+// 图片上传地址
+const { url } = toRefs(props);
+// 可上传文件数目
+const { limit } = toRefs(props);
+// 接收上传的文件类型
+const { accept } = toRefs(props);
+// 文件列表的类型--picture-card---picture
+const { listType } = toRefs(props);
+// 文件提醒
+const { tip } = toRefs(props);
+// 已有数据,赋值,预览
+const { list } = toRefs(props);
+const { model } = toRefs(props);
+// const list = ref<UploadUserFile[]>([]);
+
+const emit = defineEmits(['change']);
+// 图片预览
+const filePreview = (file: { url: string }) => {
+  // this.dialog = { show: true, url: file.url };
+  window.open(file.url);
+};
+// 只允许上传多少个文件
+const outLimit = () => {
+  ElMessage.error(`只允许上传${limit.value}个文件`);
+};
+// 上传成功,response:成功信息,file:图片信息,fileList:图片列表
+const onSuccess = (response: { errcode: string | number; errmsg: string; uri: string }, file: { name: string }, fileList: any) => {
+  if (response.errcode !== 0) {
+    ElMessage({ type: 'error', message: '删除成功' });
+    return;
+  }
+  let ponse = _.omit(response, ['errcode', 'errmsg']);
+  let arr: Ref<ListItem[]> = _.cloneDeep(list);
+  if (_.isArray(list.value)) {
+    arr.value.push({ ...ponse, name: file.name, url: `${import.meta.env.VITE_APP_HOST}${response.uri}` });
+  } else {
+    arr.value = [{ ...ponse, name: file.name, url: `${import.meta.env.VITE_APP_HOST}${response.uri}` }];
+  }
+  emit('change', { model: model.value, value: arr.value });
+};
+// 删除图片
+const onRemove = (file: { id: any; uri: string }, fileList: any) => {
+  // let arr: Ref<ListItem[]> = _.cloneDeep(list);
+  // let info = arr.value.filter((f) => f.id != file.id);
+  // emit('change', info);
+  return true;
+};
+
+// #endregion
+</script>
+
+<style lang="scss" scoped></style>

+ 57 - 0
src/components/frame/file-1.vue

@@ -0,0 +1,57 @@
+<template>
+  <div id="file-1">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-form :model="form" ref="formRef" label-width="auto">
+          <el-form-item label="佐证资料" prop="file">
+            <component :is="CUpload" :limit="limit" :url="url" :list="form.file" @change="onChange" style="width: 100%"></component>
+          </el-form-item>
+          <el-col :span="24" class="btn" v-if="!noEdit">
+            <el-button type="primary" @click="onSubmit()">确定</el-button>
+            <el-button type="danger" @click="toReset()">取消</el-button>
+          </el-col>
+        </el-form>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup lang="ts">
+import CUpload from '@/components/c-upload.vue';
+import type { Ref } from 'vue';
+import { ref, toRefs } from 'vue';
+import type { FormInstance } from 'element-plus';
+interface dataItem {}
+let limit: Ref<number> = ref(6);
+// let url: Ref<string> = ref('/files/freeLabel/outcome/upload');
+const formRef = ref<FormInstance>();
+// #region 参数传递
+const props = defineProps({
+  form: { type: Object, default: () => {} },
+  noEdit: { type: Boolean, default: () => false },
+  url: { type: String, default: () => '/files/freeLabel/upload' },
+});
+const { form } = toRefs(props);
+const { noEdit } = toRefs(props);
+const { url } = toRefs(props);
+// #endregion
+
+const emit = defineEmits(['onSubmit', 'resetForm']);
+const onChange = (e: { model: string; value: Array<dataItem> }) => {
+  const { model, value } = e;
+  form.value[model] = value;
+};
+const onSubmit = () => {
+  emit('onSubmit', form.value);
+};
+// 重置
+const toReset = () => {
+  form.value = { file: [] };
+  emit('resetForm');
+};
+</script>
+<style scoped>
+.btn {
+  text-align: center;
+}
+</style>

+ 69 - 0
src/components/frame/wang-editor.vue

@@ -0,0 +1,69 @@
+<template>
+  <div id="editor">
+    <div style="border: 1px solid #ccc">
+      <Toolbar style="border-bottom: 1px solid #ccc" :editor="editorRef" :defaultConfig="toolbarConfig" :mode="mode" />
+      <Editor style="height: 500px; overflow-y: hidden" v-model="valueHtml" :defaultConfig="editorConfig" :mode="mode" @onCreated="onCreated" />
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import '@wangeditor/editor/dist/css/style.css'; // 引入 css
+import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
+import type { Ref } from 'vue';
+import { ref, toRefs, onBeforeUnmount, shallowRef, computed } from 'vue';
+interface EmitEvent {
+  (e: 'update:modelValue', params: string): void;
+}
+// #region 参数传递
+const props = defineProps({
+  modelValue: { type: String, default: () => '' },
+  mode: { type: String, default: () => 'default' },
+  url: { type: String, default: () => '' },
+});
+const { modelValue } = toRefs(props);
+const { mode } = toRefs(props);
+const { url } = toRefs(props);
+// #endregion
+
+const editorRef = shallowRef();
+const onCreated = (editor: string) => {
+  editorRef.value = Object.seal(editor); // 一定要用 Object.seal() ,否则会报错
+};
+
+const emit = defineEmits<EmitEvent>();
+const valueHtml = computed({
+  get() {
+    return modelValue.value;
+  },
+  set(value: string) {
+    emit('update:modelValue', value);
+  },
+});
+const customPicInsert = (result: { errcode: number; uri: string; name: string }, insertFn: any) => {
+  const { errcode, uri, name } = result;
+  const url = `${import.meta.env.VITE_APP_HOST}${uri}`;
+  if (errcode === 0) {
+    insertFn(url, name);
+  }
+};
+let editorConfig: Ref<object> = ref({
+  placeholder: '请输入内容...',
+  MENU_CONF: { uploadImage: { server: url, customInsert: customPicInsert } },
+});
+let toolbarConfig: Ref<object> = ref({
+  // excludeKeys: ['insertImage', 'insertVideo', 'uploadVideo', 'video'],
+});
+onBeforeUnmount(() => {
+  const editor = editorRef.value;
+  if (editor == null) return;
+  editor.destroy();
+});
+</script>
+
+<style src="@wangeditor/editor/dist/css/style.css"></style>
+<style scoped>
+.editor {
+  overflow-y: hidden;
+}
+</style>

+ 28 - 68
src/components/studio-one-green/home-1.vue

@@ -1,81 +1,41 @@
 <template>
   <div id="home">
-    <el-container class="main" :style="{ background: styleInfo.main_bg_color }">
-      <el-aside class="one" :style="{ background: styleInfo.aside_bg_color, 'border-color': styleInfo.aside_border_color }">
-        <sidebar1></sidebar1>
-      </el-aside>
-      <el-container class="two" :style="{ background: styleInfo.con_bg_color }">
-        <el-header class="two_1">
-          <header1></header1>
-        </el-header>
-        <el-main class="two_2" :style="{ background: styleInfo.conmain_bg_color, 'border-color': styleInfo.aside_border_color }">
-          <router-view></router-view>
+    <el-container>
+      <el-header>
+        <HomeHead></HomeHead>
+      </el-header>
+      <el-container>
+        <el-aside class="one">
+          <HomeLeft></HomeLeft>
+        </el-aside>
+        <el-main class="two">
+          <el-scrollbar>
+            <router-view></router-view>
+          </el-scrollbar>
         </el-main>
       </el-container>
     </el-container>
   </div>
 </template>
 <script setup lang="ts">
-import { studio_style_Info } from '../../layout/site';
-import type { Ref } from 'vue';
-import { ref, onMounted, getCurrentInstance } from 'vue';
-import sidebar1 from './parts/header-1.vue';
-import header1 from './parts/sidebar-1.vue';
-let type: Ref<string> = ref('1');
-let styleInfo = studio_style_Info;
+import HomeLeft from './homeParts/left-1.vue';
+import HomeHead from './homeParts/header-1.vue';
 </script>
-<!-- <script>
-import { studio_style_Info } from '../../layout/site';
-import { mapState, createNamespacedHelpers } from 'vuex';
-export default {
-  name: 'home',
-  props: {},
-  components: {
-    header1: () => import('./parts/header-1.vue'),
-    sidebar1: () => import('./parts/sidebar-1.vue'),
-  },
-  data: function () {
-    return {
-      styleInfo: studio_style_Info,
-    };
-  },
-  created() {},
-  methods: {},
-  computed: {
-    ...mapState(['user']),
-  },
-  metaInfo() {
-    return { title: this.$route.meta.title };
-  },
-  watch: {
-    test: {
-      deep: true,
-      immediate: true,
-      handler(val) {},
-    },
-  },
-}; 
-</script>-->
 
-<style lang="scss" scoped>
-.main {
-  display: flex;
-  width: 100vw;
-  height: 100vh;
-  .one {
-    border-radius: 10px;
-    margin: 0.5vw;
-    padding: 0.5vw;
-    border: 1px solid;
-  }
-  .two {
-    min-width: 1200px;
-    .two_2 {
-      border-radius: 10px;
-      margin: 0.5vw;
-      padding: 0.5vw;
-      border: 1px solid;
-    }
+<style scoped lang="scss">
+.el-header {
+  padding: 0;
+  background-color: $red;
+  border-bottom: 2px solid $white;
+}
+.one {
+  width: 200px;
+  border-right: 2px solid $white;
+}
+.two {
+  height: 92vh;
+  .router-view {
+    height: 92vh;
   }
 }
 </style>

+ 0 - 63
src/components/studio-one-green/home-2.vue

@@ -1,63 +0,0 @@
-<template>
-  <div id="home">
-    <el-container class="main">
-      <el-header>
-        <HomeHead></HomeHead>
-      </el-header>
-      <el-container class="two">
-        <el-aside width="300px">
-          <HomeLeft></HomeLeft>
-        </el-aside>
-        <el-main>
-          <el-col :span="24" class="two_1">
-            <router-view></router-view>
-          </el-col>
-        </el-main>
-      </el-container>
-    </el-container>
-  </div>
-</template>
-
-<script setup lang="ts">
-import HomeLeft from './parts1/header-1.vue';
-import HomeHead from './parts1/sidebar-1.vue';
-</script>
-
-<style lang="scss" scoped>
-.main {
-  display: flex;
-  overflow: hidden;
-  width: 100vw;
-  height: 100vh;
-  padding: 10px;
-  background-color: #fff2cc;
-  .el-header {
-    padding: 10px;
-    margin: 0 0 10px 0;
-    background-color: #e2f0d9;
-    border-radius: 10px;
-    border: 1px solid #727e96;
-  }
-  .two {
-    .el-aside {
-      background-color: #e2f0d9;
-      border-radius: 10px;
-      padding: 0.5vw;
-      margin: 0 0.5vw 0 0;
-      border: 1px solid #727e96;
-    }
-    .el-main {
-      padding: 0;
-      border-radius: 10px;
-      background-color: #dae3f3;
-      border: 1px solid #727e96;
-      .two_1 {
-        display: flex;
-        height: 90vh;
-        padding: 10px;
-        flex-direction: column;
-      }
-    }
-  }
-}
-</style>

+ 0 - 9
src/components/studio-one-green/home-3.vue

@@ -1,9 +0,0 @@
-<template>
-  <div id="home-3">
-    <router-view></router-view>
-  </div>
-</template>
-
-<script lang="ts" setup></script>
-
-<style lang="scss" scoped></style>

+ 34 - 73
src/components/studio-one-green/home.vue

@@ -1,80 +1,41 @@
 <template>
   <div id="home">
-    <home1 v-if="type == '1'"></home1>
-    <home2 v-else-if="type == '2'"></home2>
-    <home3 v-else-if="type == '3'"></home3>
+    <el-container>
+      <el-header>
+        <HomeHead></HomeHead>
+      </el-header>
+      <el-container>
+        <el-aside class="one">
+          <HomeLeft></HomeLeft>
+        </el-aside>
+        <el-main class="two">
+          <el-scrollbar>
+            <router-view></router-view>
+          </el-scrollbar>
+        </el-main>
+      </el-container>
+    </el-container>
   </div>
 </template>
 <script setup lang="ts">
-import type { Ref } from 'vue';
-import { ref, onMounted, getCurrentInstance } from 'vue';
-import home1 from './home-1.vue';
-import home2 from './home-2.vue';
-import home3 from './home-3.vue';
-let type: Ref<string> = ref('1');
+import HomeLeft from './homeParts/left-1.vue';
+import HomeHead from './homeParts/header-1.vue';
 </script>
 
-<!-- <script>
-import { mapState, createNamespacedHelpers } from 'vuex';
-const { mapActions } = createNamespacedHelpers('role');
-const { mapActions: module } = createNamespacedHelpers('module');
-export default {
-  name: 'home',
-  props: {},
-  components: {
-    home1: () => import('./home-1.vue'),
-    home2: () => import('./home-2.vue'),
-    home3: () => import('./home-3.vue'),
-  },
-  data: function () {
-    return {
-      type: '1',
-    };
-  },
-  created() {},
-  methods: {
-    ...mapActions(['um']),
-    ...module({ mQuery: 'query' }),
-    async searchType(e) {
-      let name = process.env.VUE_APP_ROUTER;
-      let res = await this.mQuery({ name: name, is_use: 'Y' });
-      if (res && res.errcode == '0') {
-        if (res.total > 0) {
-          let moduleInfo = res.data[0];
-          let roleInfo = await this.um();
-          if (roleInfo.errcode == '0') {
-            if (roleInfo.data) {
-              let menus = roleInfo.data[moduleInfo._id];
-              if (menus && menus.length > 0) {
-                if (e && e.role_type == '1') this.$set(this, `type`, '1');
-                else if ((e && e.role_type == '2') || (e && e.role_type == '3')) this.$set(this, `type`, '2');
-                localStorage.setItem('is_role', true);
-              } else {
-                this.$set(this, `type`, '2');
-                localStorage.setItem('is_role', false);
-              }
-            }
-          }
-        }
-      } else {
-        this.$message({ message: `${res.errmsg}`, type: 'error' });
-      }
-    },
-  },
-  computed: {
-    ...mapState(['user']),
-  },
-  metaInfo() {
-    return { title: this.$route.meta.title };
-  },
-  watch: {
-    user: {
-      deep: true,
-      immediate: true,
-      handler(val) {
-        if (val && val._id) this.searchType(val);
-      },
-    },
-  },
-};
-</script> -->
+<style scoped lang="scss">
+.el-header {
+  padding: 0;
+  background-color: $red;
+  border-bottom: 2px solid $white;
+}
+.one {
+  width: 200px;
+  border-right: 2px solid $white;
+}
+.two {
+  height: 92vh;
+  .router-view {
+    height: 92vh;
+  }
+}
+</style>

+ 73 - 0
src/components/studio-one-green/homeParts/header-1.vue

@@ -0,0 +1,73 @@
+<template>
+  <el-col :span="24" class="main">
+    <el-row class="head">
+      <el-col :span="8" class="left">
+        <el-image :src="data.imgUrl" class="image"></el-image>
+        <span>{{ webInfo.zhTitle }}-管理中心</span>
+      </el-col>
+      <el-col :span="16" class="right">
+        <span>{{ data.user.name || '游客' }}</span>
+        <el-button type="danger" @click="logout()">退出登录</el-button>
+      </el-col>
+    </el-row>
+  </el-col>
+</template>
+
+<script setup lang="ts">
+import { reactive, ref } from 'vue';
+import type { Ref } from 'vue';
+import { studio_style_Info } from '@/layout/site';
+// let webInfo = studio_style_Info.webInfo;
+const data = reactive({
+  name: '基础动态研究管理平台',
+  user: { name: '王泓璎' },
+  imgUrl: new URL('@/assets/image/logo.png', import.meta.url).href,
+});
+const logout = () => {};
+console.log(studio_style_Info);
+</script>
+
+<style scoped>
+.head {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  padding: 0 10px 0 5px;
+}
+.left {
+  line-height: 60px;
+}
+.left span {
+  display: inline-block;
+  margin: 0 10px;
+  font-size: 24px;
+  color: var(--vt-c-white);
+  font-weight: bold;
+  font-family: cursive;
+}
+.left .image {
+  background: var(--vt-c-white);
+  height: 32px;
+  width: 32px;
+  border-radius: 90px;
+  top: 5px;
+}
+.right {
+  text-align: right;
+  /* line-height: 60px; */
+  word-break: keep-all;
+  white-space: nowrap;
+}
+.right i {
+  position: relative;
+  top: 5px;
+  margin: 0px 15px;
+  font-size: 30px;
+  color: var(--vt-c-white);
+}
+.right span {
+  color: var(--vt-c-white);
+  font-size: 16px;
+  padding: 0 15px 0 0px;
+}
+</style>

+ 98 - 0
src/components/studio-one-green/homeParts/left-1.vue

@@ -0,0 +1,98 @@
+<template>
+  <div class="main">
+    <el-menu :collapse="false" unique-opened router background-color="#66363c">
+      <template v-for="item in items">
+        <!-- 二级菜单 -->
+        <template v-if="item.type === '0'">
+          <el-sub-menu :index="item._id || item.index" :key="item._id">
+            <template v-slot:title>
+              <span>{{ item.name }}</span>
+            </template>
+            <template v-for="subItem in item.children">
+              <!-- 三级菜单 -->
+              <el-sub-menu
+                v-if="subItem.children && subItem.children.length > 0 && subItem.children.every((f:any) => f.type === '0' || f.type === '1')"
+                :index="subItem._id"
+                :key="subItem._id"
+              >
+                <template v-slot:title>
+                  <span>{{ subItem.name }}</span>
+                </template>
+                <el-menu-item v-for="(threeItem, i) in subItem.children" :key="i" :index="threeItem.path">
+                  <template v-slot:title>
+                    <span>{{ threeItem.name }}</span>
+                  </template>
+                </el-menu-item>
+              </el-sub-menu>
+              <el-menu-item v-else :index="subItem.path" :key="subItem.path">
+                <template v-slot:title>
+                  <span>{{ subItem.name }}</span>
+                </template>
+              </el-menu-item>
+            </template>
+          </el-sub-menu>
+        </template>
+        <!-- 一级菜单 -->
+        <template v-else>
+          <el-menu-item :index="item.path" :key="item.path">
+            <span>{{ item.name }}</span>
+          </el-menu-item>
+        </template>
+      </template>
+    </el-menu>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue';
+import type { Ref } from 'vue';
+// import { project_module_menus } from '@/layout/site';
+
+// 请求列表
+let items: Ref<any[]> = ref([]);
+// items.value = project_module_menus;
+</script>
+
+<style scoped>
+.el-menu {
+  height: 92.5vh;
+  overflow-y: auto;
+}
+.el-menu-item {
+  color: var(--vt-c-white);
+  font-size: 16px;
+  font-weight: 500;
+}
+.el-menu-item span {
+  overflow-y: auto;
+  overflow-x: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+:deep().el-sub-menu__title {
+  color: var(--vt-c-white);
+  font-size: 16px;
+  font-weight: 500;
+}
+:deep().el-sub-menu__title span {
+  overflow-y: auto;
+  overflow-x: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+.el-menu-item.is-active {
+  color: var(--vt-c-black) !important;
+  background-color: var(--vt-c-white) !important;
+}
+.el-menu-item:hover {
+  color: var(--vt-c-black) !important;
+  background-color: var(--vt-c-white) !important;
+}
+.el-menu::-webkit-scrollbar {
+  width: 2px;
+}
+.el-menu::-webkit-scrollbar-thumb {
+  border-radius: 10px;
+  background: rgb(255, 255, 255);
+}
+</style>

+ 0 - 101
src/components/studio-one-green/parts/header-1.vue

@@ -1,101 +0,0 @@
-<template>
-  <div id="header-1">
-    <el-row>
-      <el-col :span="24" class="main">
-        <el-col :span="8" class="one">
-          <span>欢迎进入</span>
-          <span>{{ siteInfo.zhTitle }}</span>
-        </el-col>
-        <el-col :span="16" class="two">
-          <el-button
-            size="small"
-            plain
-            v-for="(item, index) in moduleList"
-            :key="index"
-            @click="modulePath(item)"
-            :class="[active == item.active ? 'active' : '']"
-            >{{ item.name }}</el-button
-          >
-          <template v-slot:dropdown>
-            <el-dropdown @command="toDrop">
-              <el-button type="danger" plain>
-                {{ user && user._id ? user.name || user.unit_name || user.nick_name : '暂无昵称' }}
-                <i class="el-icon-arrow-down el-icon--right"></i>
-              </el-button>
-
-              <el-dropdown-menu>
-                <el-dropdown-item icon="el-icon-user" command="center">个人中心</el-dropdown-item>
-                <el-dropdown-item icon="el-icon-switch-button" command="logout">退出登录</el-dropdown-item>
-              </el-dropdown-menu>
-            </el-dropdown>
-          </template>
-        </el-col>
-      </el-col>
-    </el-row>
-  </div>
-</template>
-<script setup lang="ts">
-import { studio_style_Info, project_module_menus } from '@/layout/site';
-import { reactive, ref, onMounted } from 'vue';
-import type { Ref } from 'vue';
-let siteInfo = studio_style_Info.webInfo;
-let active = 3;
-let moduleList: Ref<any[]> = ref([]);
-let user: Ref<{ _id: string; name: string; nick_name: string; unit_name: string }> = ref({ _id: '', name: '', nick_name: '', unit_name: '' });
-onMounted(async () => {
-  await search();
-});
-const search = () => {
-  // let menu = project_module_menus.filter((i) => i.type.includes(process.env.VUE_APP_ROUTER));
-  // if (menu) this.$set(this, `moduleList`, menu);
-  moduleList.value = project_module_menus;
-};
-const toDrop = (e: any) => {
-  if (e == 'logout') {
-    localStorage.removeItem('token');
-    // window.location.href = `${process.env.VUE_APP_HOST}`;
-  } else if (e == 'center') {
-    // this.$router.push({ path: '/userInfo/center' });
-  }
-};
-const toPath = (e: any) => {
-  // this.$router.push({ path: `${e}` });
-};
-// 模块跳转
-const modulePath = (e: any) => {
-  window.location.href = `${e.path}`;
-};
-</script>
-
-<style lang="scss" scoped>
-.main {
-  .one {
-    text-align: left;
-    margin: 1vw 0;
-
-    span {
-      font-weight: bold;
-      font-size: 20px;
-    }
-    span:nth-child(1) {
-      color: #ff0000;
-
-      font-size: 25px;
-      padding: 0 5px 0 0;
-    }
-  }
-  .two {
-    text-align: right;
-    margin: 0.8vw 0;
-    button {
-      margin: 0 0 0 10px;
-    }
-    .el-button {
-      margin: 0 0 0 10px;
-    }
-    .active {
-      color: #07c4a8;
-    }
-  }
-}
-</style>

+ 0 - 152
src/components/studio-one-green/parts/sidebar-1.vue

@@ -1,152 +0,0 @@
-<template>
-  <div id="aside-1">
-    <el-row>
-      <el-col :span="24" class="aside">
-        <el-menu
-          :default-active="onRoutes"
-          unique-opened
-          router
-          :background-color="styleInfo.menus_bg_color"
-          :text-color="styleInfo.menus_txt_color"
-          :active-text-color="styleInfo.menus_actxt_color"
-        >
-          <template v-for="item in items">
-            <template v-if="item.type === '0'">
-              <el-submenu :index="item._id" :key="item._id">
-                <template v-slot:title>
-                  <i :class="['iconfont', item.icon]"></i>
-                  <span>{{ item.name }}</span>
-                </template>
-                <template v-for="subItem in item.children">
-                  <el-submenu v-if="subItem.children && subItem.children.length > 0" :index="subItem._id" :key="subItem._id">
-                    <template v-slot:title>
-                      <i :class="['iconfont', subItem.icon]"></i>
-                      <span>{{ subItem.name }}</span>
-                    </template>
-                    <el-menu-item v-for="(threeItem, i) in subItem.children" :key="i" :index="threeItem.path">
-                      <template v-slot:title>
-                        <i :class="['iconfont', threeItem.icon]"></i>
-                        <span>{{ threeItem.name }}</span>
-                      </template>
-                    </el-menu-item>
-                  </el-submenu>
-                  <el-menu-item v-else :index="subItem.path" :key="subItem.path">
-                    <template v-slot:title>
-                      <i :class="['iconfont', subItem.icon]"></i>
-                      <span>{{ subItem.name }}</span>
-                    </template>
-                  </el-menu-item>
-                </template>
-              </el-submenu>
-            </template>
-            <template v-else>
-              <el-menu-item :index="item.path" :key="item.path">
-                <i :class="['iconfont', item.icon]"></i>
-                <span>{{ item.name }}</span>
-              </el-menu-item>
-            </template>
-          </template>
-        </el-menu>
-      </el-col>
-    </el-row>
-  </div>
-</template>
-<script setup lang="ts">
-import type { Ref } from 'vue';
-import { ref, onMounted, getCurrentInstance } from 'vue';
-import { studio_style_Info } from '../../../layout/site';
-let items: Ref<any[]> = ref([]);
-let styleInfo = studio_style_Info;
-const getMenu = async (e: any) => {
-  let name = process.env.VUE_APP_ROUTER;
-  let res = await this.mQuery({ name: name, is_use: 'Y' });
-  if (res && res.errcode == '0') {
-    if (res.total > 0) {
-      let moduleInfo = res.data[0];
-      let roleInfo = await this.um();
-      if (roleInfo.errcode == '0') {
-        if (roleInfo.data) {
-          let menus = roleInfo.data[moduleInfo._id];
-          if (menus && menus.length > 0) {
-            items.value = menus;
-          }
-        }
-      }
-    }
-  } else {
-    this.$message({ message: `${res.errmsg}`, type: 'error' });
-  }
-};
-</script>
-<!-- <script>
-
-import { mapState, createNamespacedHelpers } from 'vuex';
-const { mapActions } = createNamespacedHelpers('role');
-const { mapActions: module } = createNamespacedHelpers('module');
-export default {
-  name: 'aside-1',
-  props: {},
-  components: {},
-  data: function () {
-    return {
-      items: [],
-      styleInfo: studio_style_Info,
-    };
-  },
-  created() {},
-  methods: {
-    ...mapActions(['um']),
-    ...module({ mQuery: 'query' }),
-    async getMenu(e) {
-      let name = process.env.VUE_APP_ROUTER;
-      let res = await this.mQuery({ name: name, is_use: 'Y' });
-      if (res && res.errcode == '0') {
-        if (res.total > 0) {
-          let moduleInfo = res.data[0];
-          let roleInfo = await this.um();
-          if (roleInfo.errcode == '0') {
-            if (roleInfo.data) {
-              let menus = roleInfo.data[moduleInfo._id];
-              if (menus && menus.length > 0) {
-                this.$set(this, `items`, menus);
-              }
-            }
-          }
-        }
-      } else {
-        this.$message({ message: `${res.errmsg}`, type: 'error' });
-      }
-    },
-  },
-  computed: {
-    ...mapState(['user']),
-    onRoutes() {
-      return this.$route.path;
-    },
-  },
-  metaInfo() {
-    return { title: this.$route.meta.title };
-  },
-  watch: {
-    user: {
-      deep: true,
-      immediate: true,
-      handler(val) {
-        if (val && val._id) this.getMenu(val);
-        else this.$message({ message: `暂无用户信息,无法获取菜单信息`, type: 'error' });
-      },
-    },
-  },
-};
-</script> -->
-
-<style lang="scss" scoped>
-.el-menu-item.is-active {
-  background-color: #65cd94 !important;
-}
-.el-menu-item:focus,
-.el-menu-item:hover {
-  background-color: #65cd94 !important;
-  color: #ffffff !important;
-}
-</style>

+ 0 - 112
src/components/studio-one-green/parts1/header-1.vue

@@ -1,112 +0,0 @@
-<template>
-  <div id="header-1">
-    <el-row>
-      <el-col :span="24" class="main">
-        <el-col :span="8" class="one">
-          <span>{{ siteInfo.zhTitle }}</span>
-        </el-col>
-        <el-col :span="16" class="two">
-          <el-button
-            size="small"
-            plain
-            v-for="(item, index) in moduleList"
-            :key="index"
-            @click="modulePath(item)"
-            :class="[active == item.active ? 'active' : '']"
-            >{{ item.name }}</el-button
-          >
-          <el-dropdown @command="toDrop">
-            <el-button type="danger" plain>
-              {{ user && user._id ? user.name || user.unit_name || user.nick_name : '暂无昵称' }}
-              <i class="el-icon-arrow-down el-icon--right"></i>
-            </el-button>
-            <el-dropdown-menu>
-              <el-dropdown-item icon="el-icon-user" command="center">个人中心</el-dropdown-item>
-              <el-dropdown-item icon="el-icon-switch-button" command="logout">退出登录</el-dropdown-item>
-            </el-dropdown-menu>
-          </el-dropdown>
-        </el-col>
-      </el-col>
-    </el-row>
-  </div>
-</template>
-
-<script>
-import { studio_style_Info, project_module_menus } from '../../../layout/site';
-import { mapState, createNamespacedHelpers } from 'vuex';
-export default {
-  name: 'header-1',
-  props: {},
-  components: {},
-  data: function () {
-    return {
-      siteInfo: studio_style_Info.webInfo,
-      active: 3,
-      moduleList: [],
-    };
-  },
-  created() {
-    this.search();
-  },
-  methods: {
-    search() {
-      // let menu = project_module_menus.filter((i) => i.type.includes(process.env.VUE_APP_ROUTER));
-      // if (menu) this.$set(this, `moduleList`, menu);
-      this.$set(this, `moduleList`, project_module_menus);
-    },
-    toDrop(e) {
-      if (e == 'logout') {
-        localStorage.removeItem('token');
-        window.location.href = `${import.meta.env.VUE_APP_HOST}`;
-      } else if (e == 'center') {
-        this.$router.push({ path: '/userInfo/center' });
-      }
-    },
-    toPath(e) {
-      this.$router.push({ path: `${e}` });
-    },
-    // 模块跳转
-    modulePath(e) {
-      window.location.href = `${e.path}`;
-    },
-  },
-  computed: {
-    ...mapState(['user']),
-  },
-  metaInfo() {
-    return { title: this.$route.meta.title };
-  },
-  watch: {
-    test: {
-      deep: true,
-      immediate: true,
-      handler(val) {},
-    },
-  },
-};
-</script>
-
-<style lang="scss" scoped>
-.main {
-  .one {
-    span {
-      display: inline-block;
-      background-color: #ffc000;
-      padding: 8px 10px;
-      border: 1px solid #ffffff;
-    }
-  }
-  .two {
-    text-align: right;
-    button {
-      margin: 0 0 0 10px;
-    }
-    .el-button {
-      margin: 0 0 0 10px;
-    }
-    .active {
-      color: #07c4a8;
-    }
-  }
-}
-</style>

+ 0 - 126
src/components/studio-one-green/parts1/sidebar-1.vue

@@ -1,126 +0,0 @@
-<template>
-  <div id="aside-1">
-    <el-row>
-      <el-col :span="24" class="aside">
-        <el-menu
-          :default-active="onRoutes"
-          unique-opened
-          router
-          :background-color="styleInfo.menus_bg_color"
-          :text-color="styleInfo.menus_txt_color"
-          :active-text-color="styleInfo.menus_actxt_color"
-        >
-          <template v-for="item in items">
-            <template v-if="item.type === '0'">
-              <el-submenu :index="item._id" :key="item._id">
-                <template >
-                  <i :class="['iconfont', item.icon]"></i>
-                  <span >{{ item.name }}</span>
-                </template>
-                <template v-for="subItem in item.children">
-                  <el-submenu v-if="subItem.children && subItem.children.length > 0" :index="subItem._id" :key="subItem._id">
-                    <template >
-                      <i :class="['iconfont', subItem.icon]"></i>
-                      <span >{{ subItem.name }}</span>
-                    </template>
-                    <el-menu-item v-for="(threeItem, i) in subItem.children" :key="i" :index="threeItem.path">
-                      <template >
-                        <i :class="['iconfont', threeItem.icon]"></i>
-                        <span >{{ threeItem.name }}</span>
-                      </template>
-                    </el-menu-item>
-                  </el-submenu>
-                  <el-menu-item v-else :index="subItem.path" :key="subItem.path">
-                    <template >
-                      <i :class="['iconfont', subItem.icon]"></i>
-                      <span >{{ subItem.name }}</span>
-                    </template>
-                  </el-menu-item>
-                </template>
-              </el-submenu>
-            </template>
-            <template v-else>
-              <el-menu-item :index="item.path" :key="item.path">
-                <i :class="['iconfont', item.icon]"></i>
-                <span >{{ item.name }}</span>
-              </el-menu-item>
-            </template>
-          </template>
-        </el-menu>
-      </el-col>
-    </el-row>
-  </div>
-</template>
-
-<script>
-import { studio_style_Info } from '../../../layout/site';
-import { mapState, createNamespacedHelpers } from 'vuex';
-const { mapActions } = createNamespacedHelpers('role');
-const { mapActions: module } = createNamespacedHelpers('module');
-export default {
-  name: 'aside-1',
-  props: {},
-  components: {},
-  data: function () {
-    return {
-      items: [],
-      styleInfo: studio_style_Info,
-    };
-  },
-  created() {},
-  methods: {
-    ...mapActions(['um']),
-    ...module({ mQuery: 'query' }),
-    async getMenu(e) {
-      let name = import.meta.env.VUE_APP_ROUTER;
-      let res = await this.mQuery({ name: name, is_use: 'Y' });
-      if (res && res.errcode == '0') {
-        if (res.total > 0) {
-          let moduleInfo = res.data[0];
-          let roleInfo = await this.um();
-          if (roleInfo.errcode == '0') {
-            if (roleInfo.data) {
-              let menus = roleInfo.data[moduleInfo._id];
-              if (menus && menus.length > 0) {
-                this.$set(this, `items`, menus);
-              }
-            }
-          }
-        }
-      } else {
-        this.$message({ message: `${res.errmsg}`, type: 'error' });
-      }
-    },
-  },
-  computed: {
-    ...mapState(['user']),
-    onRoutes() {
-      return this.$route.path;
-    },
-  },
-  metaInfo() {
-    return { title: this.$route.meta.title };
-  },
-  watch: {
-    user: {
-      deep: true,
-      immediate: true,
-      handler(val) {
-        if (val && val._id) this.getMenu(val);
-        else this.$message({ message: `暂无用户信息,无法获取菜单信息`, type: 'error' });
-      },
-    },
-  },
-};
-</script>
-
-<style lang="scss" scoped>
-.el-menu-item.is-active {
-  background-color: #65cd94 !important;
-}
-.el-menu-item:focus,
-.el-menu-item:hover {
-  background-color: #65cd94 !important;
-  color: #ffffff !important;
-}
-</style>

+ 0 - 793
src/layout/site.ts

@@ -1,57 +1,3 @@
-// 网站基本设置
-export const webInfo = {
-  display: true,
-  zhTitle: '基础研究动态管理平台',
-  enTitle: 'Dynamic management platform for basic research',
-  logo_url: new URL('../assets/logo.png'),
-  user_url: new URL('../assets/user.png'),
-  content: 'Copyright  2018-2022 free All Rights Reserved.',
-  smallTtitle: '基础研究动态',
-  one_title: '鼓励探索、突出原创',
-  two_title: '聚焦前沿、独辟蹊径',
-  thr_title: '需求牵引、突破瓶颈',
-  four_title: '共性导向、交叉融通'
-}
-// 超级管理员项目基本设置
-export const admin_style_Info = {
-  // 主体背景颜色
-  main_bg_color: '#f0f0f0',
-  // 头部
-  header_bg_color: '#07c4a8',
-  // 左侧菜单部分
-  aside_bg_color: '#07c4a8',
-  aside_border_color: '#ffffff',
-  // 内容显示部分
-  routerview_bg_color: '#ffffff',
-};
-// 管理员项目基本设置
-export const basic_style_Info = {
-  // 主体背景颜色
-  main_bg_color: '#f0f0f0',
-  // 头部
-  header_bg_color: '#07c4a8',
-  // 左侧菜单部分
-  aside_bg_color: '#07c4a8',
-  aside_border_color: '#ffffff',
-  // 内容显示部分
-  routerview_bg_color: '#ffffff',
-};
-// 项目管理项目基本设置
-export const project_style_Info = {
-  webInfo: {
-    display: true,
-    zhTitle: '吉林省项目动态管理平台',
-  },
-  // 主体背景颜色
-  main_bg_color: '#f0f0f0',
-  // 头部
-  header_bg_color: '#07c4a8',
-  // 左侧菜单部分
-  aside_bg_color: '#07c4a8',
-  aside_border_color: '#ffffff',
-  // 内容显示部分
-  routerview_bg_color: '#ffffff',
-};
 // 科学家工作室管理项目基本设置
 export const studio_style_Info = {
   webInfo: {
@@ -70,742 +16,3 @@ export const studio_style_Info = {
   con_bg_color: '#fff2cc',
   conmain_bg_color: '#dae3f3',
 };
-// 模块设置
-export const project_module_menus = [
-  {
-    icon: 'el-icon-user',
-    name: '基础研究动态管理平台',
-    path: '/admin',
-    type: 'basic,project,studio',
-    active: '0',
-  },
-  // {
-  //   icon: 'el-icon-user',
-  //   name: '省重点实验室',
-  //   path: '/basic',
-  //   type: 'admin,project,studio',
-  //   active: '1',
-  // },
-  {
-    icon: 'el-icon-user',
-    name: '项目管理',
-    path: '/project',
-    type: 'admin,basic,studio',
-    active: '2',
-  },
-  {
-    icon: 'el-icon-user',
-    name: '科学家工作室管理',
-    path: '/studio',
-    type: 'admin,basic,project',
-    active: '3',
-  },
-];
-// 菜单
-export const admin_menus = [
-  {
-    id: 'menus_1',
-    icon: 'el-icon-user',
-    name: '系统首页',
-    path: '/homeIndex',
-    type: '',
-  },
-  {
-    _id: 'menus_2',
-    icon: 'el-icon-user',
-    name: '系统管理',
-    type: '0',
-    children: [
-      {
-        _id: 'menus_2_1',
-        icon: 'el-icon-user',
-        name: '用户管理',
-        type: '1',
-        children: [
-          {
-            _id: 'menus_2_1_1',
-            icon: 'el-icon-user',
-            name: '管理员',
-            path: '/system/user/admin',
-          },
-          {
-            _id: 'menus_2_1_2',
-            icon: 'el-icon-user',
-            name: '依托单位',
-            path: '/system/user/unit',
-          },
-          {
-            _id: 'menus_2_1_3',
-            icon: 'el-icon-user',
-            name: '个人账号',
-            path: '/system/user/personal',
-          },
-        ],
-      },
-      {
-        _id: 'menus_2_2',
-        icon: 'el-icon-user',
-        name: '角色管理',
-        path: '/system/role',
-      },
-      {
-        _id: 'menus_2_3',
-        icon: 'el-icon-user',
-        name: '平台项目管理',
-        path: '/system/module',
-      },
-      {
-        _id: 'menus_2_4',
-        icon: 'el-icon-user',
-        name: '字典管理',
-        path: '/system/dict',
-      },
-      {
-        _id: 'menus_2_5',
-        icon: 'el-icon-user',
-        name: '地区管理',
-        path: '/system/place',
-      },
-      {
-        _id: 'menus_2_6',
-        icon: 'el-icon-user',
-        name: '通知公告',
-        path: '/system/notice',
-      },
-      {
-        _id: 'menus_2_7',
-        icon: 'el-icon-user',
-        name: '查看公告',
-        path: '/system/noticeview',
-      },
-    ],
-  },
-  {
-    _id: 'menus_3',
-    icon: 'el-icon-user',
-    name: '账号管理',
-    type: '0',
-    children: [
-      {
-        _id: 'menus_3_1',
-        icon: 'el-icon-user',
-        name: '账号信息',
-        path: '/account/info',
-      },
-      {
-        _id: 'menus_3_2',
-        icon: 'el-icon-user',
-        name: '修改密码',
-        path: '/account/updatepd',
-      },
-    ],
-  },
-];
-export const basic_menus = [
-  {
-    id: 'menus_1',
-    icon: 'el-icon-user',
-    name: '系统首页',
-    path: '/homeIndex',
-    type: '',
-  },
-  {
-    _id: 'menus_2',
-    icon: 'el-icon-user',
-    name: '二级菜单',
-    type: '0',
-    children: [
-      {
-        _id: 'menus_2_1',
-        icon: 'el-icon-user',
-        name: '二级菜单-1',
-        path: '/test/test1',
-      },
-      {
-        _id: 'menus_2_2',
-        icon: 'el-icon-user',
-        name: '三级菜单',
-        type: '2',
-        children: [
-          {
-            _id: 'menus_2_2_1',
-            icon: 'el-icon-user',
-            name: '三级菜单-1',
-            path: '/test/test2/test1',
-          },
-        ],
-      },
-    ],
-  },
-];
-// 个人用户菜单
-// export const project_menus = [
-//   {
-//     id: 'menus_1',
-//     icon: 'el-icon-user',
-//     name: '系统首页',
-//     path: '/homeIndex',
-//     type: '',
-//   },
-//   {
-//     id: 'menus_2',
-//     icon: 'el-icon-user',
-//     name: '科研项目',
-//     path: '/project',
-//     type: '',
-//   },
-//   {
-//     _id: 'menus_3',
-//     icon: 'el-icon-user',
-//     name: '项目管理',
-//     type: '0',
-//     children: [
-//       {
-//         _id: 'menus_3_1',
-//         icon: 'el-icon-user',
-//         name: '发表学术论文',
-//         path: '/project/platform/paper',
-//       },
-//       {
-//         _id: 'menus_3_2',
-//         icon: 'el-icon-user',
-//         name: '其他成果',
-//         path: '/project/platform/other',
-//       },
-//       {
-//         _id: 'menus_3_3',
-//         icon: 'el-icon-user',
-//         name: '获奖情况',
-//         path: '/project/platform/award',
-//       },
-//       {
-//         _id: 'menus_3_4',
-//         icon: 'el-icon-user',
-//         name: '成果转化',
-//         path: '/project/platform/achieve',
-//       },
-//       {
-//         _id: 'menus_3_5',
-//         icon: 'el-icon-user',
-//         name: '学术交流',
-//         type: '2',
-//         children: [
-//           {
-//             _id: 'menus_3_5_1',
-//             icon: 'el-icon-user',
-//             name: '省部级及以上活动',
-//             path: '/project/xueshu/socialservices',
-//           },
-//           {
-//             _id: 'menus_3_5_2',
-//             icon: 'el-icon-user',
-//             name: '科普活动',
-//             path: '/project/xueshu/scienceactivities',
-//           },
-//           {
-//             _id: 'menus_3_5_3',
-//             icon: 'el-icon-user',
-//             name: '发表/提交报告',
-//             path: '/project/xueshu/report',
-//           },
-//         ],
-//       },
-//       {
-//         _id: 'menus_3_6',
-//         icon: 'el-icon-user',
-//         name: '队伍建设与人才培养',
-//         type: '2',
-//         children: [
-//           {
-//             _id: 'menus_3_6_1',
-//             icon: 'el-icon-user',
-//             name: '省部级以上人才称号',
-//             path: '/project/jianshe/personnelname',
-//           },
-//           {
-//             _id: 'menus_3_6_2',
-//             icon: 'el-icon-user',
-//             name: '职称晋升',
-//             path: '/project/jianshe/title',
-//           },
-//           {
-//             _id: 'menus_3_6_3',
-//             icon: 'el-icon-user',
-//             name: '博硕培养',
-//             path: '/project/jianshe/doctor',
-//           },
-//         ],
-//       },
-//       {
-//         _id: 'menus_3_7',
-//         icon: 'el-icon-user',
-//         name: '重要进展及重大报告',
-//         path: '/project/outcome',
-//       },
-//     ],
-//   },
-//   {
-//     _id: 'menus_4',
-//     icon: 'el-icon-user',
-//     name: '项目指南建议征集',
-//     type: '0',
-//     children: [
-//       {
-//         _id: 'menus_4_1',
-//         icon: 'el-icon-user',
-//         name: '2024年度国家自然科学基金区域创新发展联合基金指南建议申报',
-//         path: '/project/guide/declare',
-//       },
-//     ],
-//   },
-// ];
-// 依托单位菜单
-// export const project_menus = [
-//   {
-//     id: 'menus_1',
-//     icon: 'el-icon-user',
-//     name: '系统首页',
-//     path: '/homeIndex',
-//     type: '',
-//   },
-//   {
-//     id: 'menus_2',
-//     icon: 'el-icon-user',
-//     name: '项目管理',
-//     path: '/project/views',
-//     type: '',
-//   },
-//   {
-//     _id: 'menus_3',
-//     icon: 'el-icon-user',
-//     name: '项目指南建议征集',
-//     type: '0',
-//     children: [
-//       {
-//         _id: 'menus_3_1',
-//         icon: 'el-icon-user',
-//         name: '建议审核',
-//         path: '/project/guide/exam',
-//       },
-//     ],
-//   },
-// ];
-// 管理员菜单
-export const project_menus = [
-  {
-    id: 'menus_1',
-    icon: 'el-icon-user',
-    name: '系统首页',
-    path: '/homeIndex',
-    type: '',
-  },
-  {
-    id: 'menus_2',
-    icon: 'el-icon-user',
-    name: '科研项目',
-    path: '/project',
-    type: '',
-  },
-  {
-    id: 'menus_3',
-    icon: 'el-icon-user',
-    name: '项目管理',
-    path: '/project/views',
-    type: '',
-  },
-  {
-    _id: 'menus_4',
-    icon: 'el-icon-user',
-    name: '项目管理',
-    type: '0',
-    children: [
-      {
-        _id: 'menus_4_1',
-        icon: 'el-icon-user',
-        name: '发表学术论文',
-        path: '/project/platform/paper',
-      },
-      {
-        _id: 'menus_4_2',
-        icon: 'el-icon-user',
-        name: '其他成果',
-        path: '/project/platform/other',
-      },
-      {
-        _id: 'menus_4_3',
-        icon: 'el-icon-user',
-        name: '获奖情况',
-        path: '/project/platform/award',
-      },
-      {
-        _id: 'menus_4_4',
-        icon: 'el-icon-user',
-        name: '成果转化',
-        path: '/project/platform/achieve',
-      },
-      {
-        _id: 'menus_4_5',
-        icon: 'el-icon-user',
-        name: '学术交流',
-        type: '2',
-        children: [
-          {
-            _id: 'menus_4_5_1',
-            icon: 'el-icon-user',
-            name: '省部级及以上活动',
-            path: '/project/xueshu/socialservices',
-          },
-          {
-            _id: 'menus_4_5_2',
-            icon: 'el-icon-user',
-            name: '科普活动',
-            path: '/project/xueshu/scienceactivities',
-          },
-          {
-            _id: 'menus_4_5_3',
-            icon: 'el-icon-user',
-            name: '发表/提交报告',
-            path: '/project/xueshu/report',
-          },
-        ],
-      },
-      {
-        _id: 'menus_4_6',
-        icon: 'el-icon-user',
-        name: '队伍建设与人才培养',
-        type: '2',
-        children: [
-          {
-            _id: 'menus_4_6_1',
-            icon: 'el-icon-user',
-            name: '省部级以上人才称号',
-            path: '/project/jianshe/personnelname',
-          },
-          {
-            _id: 'menus_4_6_2',
-            icon: 'el-icon-user',
-            name: '职称晋升',
-            path: '/project/jianshe/title',
-          },
-          {
-            _id: 'menus_4_6_3',
-            icon: 'el-icon-user',
-            name: '博硕培养',
-            path: '/project/jianshe/doctor',
-          },
-        ],
-      },
-      {
-        _id: 'menus_4_7',
-        icon: 'el-icon-user',
-        name: '重要进展及重大报告',
-        path: '/project/outcome',
-      },
-    ],
-  },
-  {
-    _id: 'menus_5',
-    icon: 'el-icon-user',
-    name: '项目指南建议征集',
-    type: '0',
-    children: [
-      {
-        _id: 'menus_5_1',
-        icon: 'el-icon-user',
-        name: '2024年度国家自然科学基金区域创新发展联合基金指南建议申报',
-        path: '/project/guide/declare',
-      },
-      {
-        _id: 'menus_5_2',
-        icon: 'el-icon-user',
-        name: '建议审核',
-        path: '/project/guide/exam',
-      },
-      {
-        _id: 'menus_5_3',
-        icon: 'el-icon-user',
-        name: '建议审核结束',
-        path: '/project/guide/endGuide',
-      },
-    ],
-  },
-];
-export const studio_menus = [
-  {
-    id: 'menus_1',
-    icon: 'el-icon-user',
-    name: '系统首页',
-    path: '/homeIndex',
-    type: '',
-  },
-  {
-    _id: 'menus_2',
-    icon: 'el-icon-user',
-    name: '用户管理',
-    type: '0',
-    children: [
-      {
-        _id: 'menus_2_1',
-        icon: 'el-icon-user',
-        name: '依托单位',
-        path: '/users/company',
-      },
-      {
-        _id: 'menus_2_2',
-        icon: 'el-icon-user',
-        name: '科学家',
-        path: '/users/scientist',
-      },
-    ],
-  },
-  {
-    _id: 'menus_3',
-    icon: 'el-icon-user',
-    name: '科学家工作室',
-    type: '0',
-    children: [
-      {
-        _id: 'menus_3_1',
-        icon: 'el-icon-user',
-        name: '信息列表',
-        path: '/studio/info',
-      },
-      {
-        _id: 'menus_3_2',
-        icon: 'el-icon-user',
-        name: '年度报告',
-        path: '/studio/year',
-      },
-      {
-        _id: 'menus_3_3',
-        icon: 'el-icon-user',
-        name: '保留资质',
-        path: '/studio/flair',
-      },
-    ],
-  },
-  {
-    _id: 'menus_4',
-    icon: 'el-icon-user',
-    name: '技术供求',
-    type: '0',
-    children: [
-      {
-        _id: 'menus_4_1',
-        icon: 'el-icon-user',
-        name: '技术支持',
-        path: '/supplydemand/support',
-      },
-      {
-        _id: 'menus_4_2',
-        icon: 'el-icon-user',
-        name: '技术需求',
-        path: '/supplydemand/demand',
-      },
-    ],
-  },
-  {
-    _id: 'menus_5',
-    icon: 'el-icon-user',
-    name: '其他内容',
-    type: '0',
-    children: [
-      {
-        _id: 'menus_4_1',
-        icon: 'el-icon-user',
-        name: '成果展示',
-        path: '/other/achieve',
-      },
-      {
-        _id: 'menus_4_2',
-        icon: 'el-icon-user',
-        name: '通知公告',
-        path: '/other/notice',
-      },
-      {
-        _id: 'menus_4_3',
-        icon: 'el-icon-user',
-        name: '相关下载',
-        path: '/other/download',
-      },
-      {
-        _id: 'menus_4_4',
-        icon: 'el-icon-user',
-        name: '联系处室',
-        path: '/other/contact',
-      },
-      {
-        _id: 'menus_4_5',
-        icon: 'el-icon-user',
-        name: '系统消息',
-        path: '/other/message',
-      },
-    ],
-  },
-];
-// 问题来源
-export const question_origin = [
-  {
-    dict_sort: '0',
-    dict_label: '企业科技问题',
-    dict_value: '企业科技问题',
-    dict_type: 'question_origin',
-    status: '0',
-    remark: '问题来源',
-  },
-  {
-    dict_sort: '0',
-    dict_label: '独立提出',
-    dict_value: '独立提出',
-    dict_type: 'question_origin',
-    status: '0',
-    remark: '问题来源',
-  },
-];
-// 企业科技问题
-export const company_question = [
-  {
-    dict_sort: '0',
-    dict_label: '基于新型锑化物超晶格异质结的高性能红外探测芯片关键技术',
-    dict_value: '基于新型锑化物超晶格异质结的高性能红外探测芯片关键技术',
-    dict_type: 'company_question',
-    status: '0',
-    remark: '企业科技问题',
-  },
-  {
-    dict_sort: '0',
-    dict_label: '结构可控的功能化水性聚氨酯基涂层的构筑、性能及其机理',
-    dict_value: '结构可控的功能化水性聚氨酯基涂层的构筑、性能及其机理',
-    dict_type: 'company_question',
-    status: '0',
-    remark: '企业科技问题',
-  },
-  {
-    dict_sort: '0',
-    dict_label: '季冻区轨道交通工程绿色纤维UHPC耐复杂环境结构性能研究',
-    dict_value: '季冻区轨道交通工程绿色纤维UHPC耐复杂环境结构性能研究',
-    dict_type: 'company_question',
-    status: '0',
-    remark: '企业科技问题',
-  },
-  {
-    dict_sort: '0',
-    dict_label: '自由曲面多阶段超精密加工工艺链数字孪生的基础研究',
-    dict_value: '自由曲面多阶段超精密加工工艺链数字孪生的基础研究',
-    dict_type: 'company_question',
-    status: '0',
-    remark: '企业科技问题',
-  },
-  {
-    dict_sort: '0',
-    dict_label: '花生高油酸性状对耐寒性的影响及其机理',
-    dict_value: '花生高油酸性状对耐寒性的影响及其机理',
-    dict_type: 'company_question',
-    status: '0',
-    remark: '企业科技问题',
-  },
-  {
-    dict_sort: '0',
-    dict_label: '寒地黑猪品种优质抗逆特性形成机理',
-    dict_value: '寒地黑猪品种优质抗逆特性形成机理',
-    dict_type: 'company_question',
-    status: '0',
-    remark: '企业科技问题',
-  },
-  {
-    dict_sort: '0',
-    dict_label: '米级量程纳米精度多自由度光栅位移测量机理与关键技术',
-    dict_value: '米级量程纳米精度多自由度光栅位移测量机理与关键技术',
-    dict_type: 'company_question',
-    status: '0',
-    remark: '企业科技问题',
-  },
-  {
-    dict_sort: '0',
-    dict_label: '通遥一体的在轨数据实时分析处理方法',
-    dict_value: '通遥一体的在轨数据实时分析处理方法',
-    dict_type: 'company_question',
-    status: '0',
-    remark: '企业科技问题',
-  },
-  {
-    dict_sort: '0',
-    dict_label: '高速电动磁浮车载超导磁体的服役可靠性与行为演变',
-    dict_value: '高速电动磁浮车载超导磁体的服役可靠性与行为演变',
-    dict_type: 'company_question',
-    status: '0',
-    remark: '企业科技问题',
-  },
-  {
-    dict_sort: '0',
-    dict_label: '伺服阀壳体磨粒流精密抛光表面完整性及多余物去除机理',
-    dict_value: '伺服阀壳体磨粒流精密抛光表面完整性及多余物去除机理',
-    dict_type: 'company_question',
-    status: '0',
-    remark: '企业科技问题',
-  },
-  {
-    dict_sort: '0',
-    dict_label: '肉牛养殖人工智能监控机制',
-    dict_value: '肉牛养殖人工智能监控机制',
-    dict_type: 'company_question',
-    status: '0',
-    remark: '企业科技问题',
-  },
-  {
-    dict_sort: '0',
-    dict_label: '新型产胶植物橡胶草高产新品种创制及其产量形成的分子机理',
-    dict_value: '新型产胶植物橡胶草高产新品种创制及其产量形成的分子机理',
-    dict_type: 'company_question',
-    status: '0',
-    remark: '企业科技问题',
-  },
-  {
-    dict_sort: '0',
-    dict_label: '黑土地农田土壤微塑料污染过程与阻控机制',
-    dict_value: '黑土地农田土壤微塑料污染过程与阻控机制',
-    dict_type: 'company_question',
-    status: '0',
-    remark: '企业科技问题',
-  },
-  {
-    dict_sort: '0',
-    dict_label: '城镇污水生物-化学耦合强化减污降碳和再生利用机制',
-    dict_value: '城镇污水生物-化学耦合强化减污降碳和再生利用机制',
-    dict_type: 'company_question',
-    status: '0',
-    remark: '企业科技问题',
-  },
-  {
-    dict_sort: '0',
-    dict_label: '基于力-像融合的智能骨折复位机器人系统',
-    dict_value: '基于力-像融合的智能骨折复位机器人系统',
-    dict_type: 'company_question',
-    status: '0',
-    remark: '企业科技问题',
-  },
-  {
-    dict_sort: '0',
-    dict_label: '冻融复杂条件下黑土石油污染光电融合膜界面探测与仿生特异感知',
-    dict_value: '冻融复杂条件下黑土石油污染光电融合膜界面探测与仿生特异感知',
-    dict_type: 'company_question',
-    status: '0',
-    remark: '企业科技问题',
-  },
-  {
-    dict_sort: '0',
-    dict_label: '基于机器视觉的汽车整车及零部件外观检测',
-    dict_value: '基于机器视觉的汽车整车及零部件外观检测',
-    dict_type: 'company_question',
-    status: '0',
-    remark: '企业科技问题',
-  },
-  {
-    dict_sort: '0',
-    dict_label: '空地湍流信道光脉冲往返传输特性基础理论',
-    dict_value: '空地湍流信道光脉冲往返传输特性基础理论',
-    dict_type: 'company_question',
-    status: '0',
-    remark: '企业科技问题',
-  },
-];