Sfoglia il codice sorgente

Merge branch 'master' of http://git.cc-lotus.info/studio_vue3/jcyjdt_studio

guhongwei 2 anni fa
parent
commit
3f75540e2f

+ 175 - 0
src/components/common/build/info.vue

@@ -0,0 +1,175 @@
+<template>
+  <div id="info">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight">
+        <el-col :span="24" class="one">
+          <el-form :model="form" :rules="{}" ref="formRef" label-width="140px">
+            <el-col :span="24" class="form_1">
+              <el-col :span="24" class="title">一、工作室建设信息</el-col>
+              <el-col :span="24" class="info">
+                <el-form-item label="单位名称">
+                  <el-input v-model="form.company_name" readonly></el-input>
+                </el-form-item>
+                <el-form-item label="单位所在地">
+                  <el-input v-model="form.address" readonly></el-input>
+                </el-form-item>
+                <el-form-item label="单位性质">
+                  <el-select v-model="form.nature" filterable clearable placeholder="请选择单位性质" style="width: 100%" disabled>
+                    <el-option v-for="i in natureList" :key="i._id" :label="i.dict_label" :value="i.dict_value"></el-option>
+                  </el-select>
+                </el-form-item>
+                <el-form-item label="拟解决技术难题或战略发展问题">
+                  <el-input
+                    v-model="form.development"
+                    placeholder="请输入拟解决技术难题或战略发展问题"
+                    type="textarea"
+                    :autosize="{ minRows: 6, maxRows: 6 }"
+                    readonly
+                  ></el-input>
+                </el-form-item>
+                <el-form-item label="所属领域">
+                  <el-select v-model="form.fields" multiple clearable filterable placeholder="请选择所属领域" style="width: 100%" disabled>
+                    <el-option v-for="i in fieldList" :key="i._id" :label="i.dict_label" :value="i.dict_value"></el-option>
+                  </el-select>
+                </el-form-item>
+                <el-form-item label="建设目标">
+                  <el-input v-model="form.target" readonly></el-input>
+                </el-form-item>
+                <el-form-item label="联系人">
+                  <el-input v-model="form.contact" readonly></el-input>
+                </el-form-item>
+                <el-form-item label="联系电话">
+                  <el-input v-model="form.phone" readonly></el-input>
+                </el-form-item>
+              </el-col>
+            </el-col>
+            <el-col :span="24" class="form_1">
+              <el-col :span="24" class="title">二、科学家入驻要求</el-col>
+              <el-col :span="24" class="info">
+                <el-form-item label="专业技术职称">
+                  <el-select v-model="form.zc" filterable clearable placeholder="请选择专业技术职称" style="width: 100%" disabled>
+                    <el-option v-for="i in zcList" :key="i._id" :label="i.dict_label" :value="i.dict_value"></el-option>
+                  </el-select>
+                </el-form-item>
+                <el-form-item label="专业领域">
+                  <el-select v-model="form.zy_fields" multiple clearable filterable placeholder="请选择专业领域" style="width: 100%" disabled>
+                    <el-option v-for="i in fieldList" :key="i._id" :label="i.dict_label" :value="i.dict_value"></el-option>
+                  </el-select>
+                </el-form-item>
+                <el-form-item label="研究方向">
+                  <span v-for="(i, index) in form.direction" :key="index" class="direction">
+                    <span>{{ index + 1 }}.</span>{{ i.name }}
+                  </span>
+                </el-form-item>
+                <el-form-item label="其他要求">
+                  <el-input v-model="form.other" placeholder="请输入其他要求" type="textarea" :autosize="{ minRows: 6, maxRows: 6 }"></el-input>
+                </el-form-item>
+              </el-col>
+            </el-col>
+          </el-form>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import type { Ref } from 'vue';
+import { ref, toRefs, watch } from 'vue';
+import { DictDataStore } from '@common/src/stores/users/sysdictdata'; // 字典表
+import type { IQueryResult } from '@/util/types.util';
+const sysdictdata = DictDataStore();
+const props = defineProps({
+  info: { type: Object, default: () => {} },
+});
+const { info } = toRefs(props);
+
+let form: Ref<{
+  contact_phone: object;
+  company_name: string;
+  address: string;
+  nature: string;
+  development: string;
+  fields: string;
+  target: string;
+  contact: string;
+  phone: string;
+  zc: string;
+  zy_fields: string;
+  direction: any[];
+  other: string;
+}> = ref({
+  contact_phone: {},
+  company_name: '',
+  address: '',
+  nature: '',
+  development: '',
+  fields: '',
+  target: '',
+  contact: '',
+  phone: '',
+  zc: '',
+  zy_fields: '',
+  direction: [],
+  other: '',
+});
+let natureList: Ref<any[]> = ref([]); // 单位性质
+let zcList: Ref<any[]> = ref([]); // 专业技术职称
+let fieldList: Ref<any[]> = ref([]); // 专业领域
+
+const search = (e) => {
+  form.value = e;
+};
+// 查询其他信息
+const searchOther = async () => {
+  // 字典表---单位性质
+  const p1: IQueryResult = await sysdictdata.query({ dict_type: 's-builddesire-nature' });
+  natureList.value = p1.data as [];
+  // 字典表---单位性质
+  const p2: IQueryResult = await sysdictdata.query({ dict_type: 's-builddesire-zc' });
+  zcList.value = p2.data as [];
+  // 字典表---单位性质
+  const p3: IQueryResult = await sysdictdata.query({ dict_type: 'studio_field' });
+  fieldList.value = p3.data as [];
+};
+watch(info, async (newVal) => {
+  await searchOther();
+  if (newVal && newVal._id) {
+    await search(newVal);
+  }
+});
+</script>
+<style lang="scss" scoped>
+.main {
+  .two {
+    padding: 0 0 10px 0;
+    .form_1 {
+      .title {
+        margin: 0 0 15px 0;
+        font-size: 20px;
+        font-family: monospace;
+        font-weight: bold;
+        span {
+          font-size: 12px;
+          color: #858585;
+        }
+      }
+    }
+    .btn {
+      text-align: center;
+    }
+  }
+}
+.direction {
+  display: inline-block;
+  background-color: #409eff;
+  border-radius: 5px;
+  padding: 0 5px;
+  margin: 0 5px 5px 0;
+  color: #ffffff;
+  line-height: 2.5;
+  span {
+    padding: 0 5px 0 0;
+  }
+}
+</style>

+ 69 - 0
src/components/common/notice/info.vue

@@ -0,0 +1,69 @@
+<template>
+  <div id="info">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight">
+        <el-col :span="24" class="one">
+          {{ info.title }}
+        </el-col>
+        <el-col :span="24" class="two">
+          <span>信息来源:{{ info.origin || '暂无' }}</span>
+          <span>发布时间:{{ info.date || '暂无' }}</span>
+        </el-col>
+
+        <el-col :span="24" class="thr" v-if="info.content">
+          <p v-html="info.content"></p>
+        </el-col>
+        <el-col :span="24" class="four" v-if="info.file && info.file.length > 0">
+          <el-col :span="24" class="four_1">附件:</el-col>
+          <el-col :span="24" class="four-2">
+            <el-link v-for="(item, index) in info.file" :key="index" :href="item.url" target="_blank"> {{ index + 1 }}.{{ item.name }} </el-link>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+<script lang="ts" setup>
+import { toRefs } from 'vue';
+const props = defineProps({
+  info: { type: Object, default: () => {} },
+});
+const { info } = toRefs(props);
+</script>
+
+<style lang="scss" scoped>
+.main {
+  .one {
+    margin: 15px 0;
+    text-align: center;
+    font-size: 30px;
+    font-family: cursive;
+    font-weight: bold;
+  }
+  .two {
+    padding: 0 0 20px 0;
+    margin: 0 0 20px 0;
+    text-align: center;
+    border-bottom: 1px dashed #cccccc;
+
+    span {
+      padding: 0 10px;
+      font-size: 14px;
+    }
+  }
+
+  .thr {
+    padding: 0 0 10px 0;
+    margin: 0 0 10px 0;
+    text-align: center;
+    border-bottom: 1px dashed #cccccc;
+  }
+  .four {
+    .four_1 {
+      font-size: 14px;
+      font-weight: bold;
+      margin: 0 0 5px 0;
+    }
+  }
+}
+</style>

+ 48 - 0
src/components/common/web/c-page.vue

@@ -0,0 +1,48 @@
+<template>
+  <div id="c-page">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <el-pagination
+            background
+            layout="total, prev, pager, next"
+            :total="total"
+            :page-size="limit"
+            v-model:current-page="currentPage"
+            @current-change="changePage"
+          >
+          </el-pagination>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+<script lang="ts" setup>
+import type { Ref } from 'vue';
+import { ref, toRefs } from 'vue';
+const props = defineProps({
+  total: { type: Number },
+  limit: { type: Number, default: 8 },
+});
+const { total } = toRefs(props);
+const { limit } = toRefs(props);
+let currentPage: Ref<number> = ref(1);
+const emit = defineEmits(['query']);
+const changePage = (page = currentPage.value) => {
+  emit('query', { skip: (page - 1) * limit.value, limit: limit.value });
+};
+</script>
+
+<style lang="scss" scoped>
+.main {
+  .one {
+    padding: 8px;
+    height: 50px;
+  }
+
+  .el-pagination {
+    position: absolute;
+    right: 10px;
+  }
+}
+</style>

+ 110 - 5
src/components/common/web/index.vue

@@ -1,15 +1,120 @@
 <template>
   <div id="index">
     <el-row>
-      <el-col :span="24" class="main"> 11111111111111111 </el-col>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <span :class="['list', active == `${index}` ? 'is_active' : '']" v-for="(item, index) in menusList" :key="index" @click="typeChange(item, index)">
+            {{ item.name }}
+          </span>
+        </el-col>
+        <el-col :span="24" class="two">
+          <template v-if="data_type == 'list'">
+            <component :is="list_component" @toView="toView"></component>
+          </template>
+          <template v-else-if="data_type == 'info'">
+            <component :is="info_component" :id="id" @toBack="toBack"></component>
+          </template>
+        </el-col>
+      </el-col>
     </el-row>
   </div>
 </template>
 
 <script setup lang="ts">
-import type { Ref } from 'vue';
-import { ref, toRefs } from 'vue';
-
+// #region 引用组件
+// 列表
+import build from '@/components/common/web/list/build.vue';
+import studio from '@/components/common/web/list/studio.vue';
+import unit from '@/components/common/web/list/unit.vue';
+import scientist from '@/components/common/web/list/scientist.vue';
+import support from '@/components/common/web/list/support.vue';
+import demand from '@/components/common/web/list/demand.vue';
+import notice from '@/components/common/web/list/notice.vue';
+import download from '@/components/common/web/list/download.vue';
+// 详情
+import builds from '@/components/common/web/info/builds.vue';
+import studios from '@/components/common/web/info/studios.vue';
+import units from '@/components/common/web/info/units.vue';
+import scientists from '@/components/common/web/info/scientists.vue';
+import supports from '@/components/common/web/info/supports.vue';
+import demands from '@/components/common/web/info/demands.vue';
+import notices from '@/components/common/web/info/notices.vue';
+import downloads from '@/components/common/web/info/downloads.vue';
+// #endregion
 
+import type { Ref } from 'vue';
+import { ref } from 'vue';
+// 菜单部分
+let active: Ref<string> = ref('0');
+let menusList: Ref<any[]> = ref([
+  { name: '科学家工作室建设意愿名录', component: build },
+  { name: '科学家工作室名录', component: studio },
+  { name: '依托单位名录', component: unit },
+  { name: '科学家名录', component: scientist },
+  { name: '技术支持', component: support },
+  { name: '技术需求', component: demand },
+  { name: '通知公告', component: notice },
+  { name: '相关下载', component: download },
+]);
+// 展示页面类型list:列表,info:详情
+let data_type: Ref<string> = ref('list');
+let list_component: Ref<any> = ref(build);
+let info_component: Ref<any> = ref(builds);
+let id: Ref<string> = ref('');
+// 类型选择
+const typeChange = (e, index) => {
+  data_type.value = 'list';
+  active.value = index;
+  list_component.value = e.component;
+};
+// 查看详情
+const toView = (e: { data; component }) => {
+  const { data, component } = e;
+  data_type.value = 'info';
+  id.value = data._id;
+  if (component == 'builds') info_component.value = builds;
+  else if (component == 'studios') info_component.value = studios;
+  else if (component == 'units') info_component.value = units;
+  else if (component == 'scientists') info_component.value = scientists;
+  else if (component == 'supports') info_component.value = supports;
+  else if (component == 'demands') info_component.value = demands;
+  else if (component == 'notices') info_component.value = notices;
+  else if (component == 'downloads') info_component.value = downloads;
+};
+// 返回
+const toBack = (component) => {
+  data_type.value = 'list';
+  if (component == 'build') list_component.value = build;
+  else if (component == 'studio') list_component.value = studio;
+  else if (component == 'unit') list_component.value = unit;
+  else if (component == 'scientist') list_component.value = scientist;
+  else if (component == 'support') list_component.value = support;
+  else if (component == 'demand') list_component.value = demand;
+  else if (component == 'notice') list_component.value = notice;
+  else if (component == 'download') list_component.value = download;
+};
 </script>
-<style scoped></style>
+<style scoped lang="scss">
+.main {
+  .one {
+    margin: 20px 0 10px 0;
+    text-align: center;
+    .list {
+      display: inline-block;
+      background-color: #a2e1f7;
+      margin: 0 10px;
+      padding: 10px;
+      border-radius: 5px;
+    }
+    .list:hover {
+      cursor: pointer;
+      background-color: #65cd94;
+      color: #ffffff;
+    }
+    .is_active {
+      background-color: #65cd94;
+      color: #ffffff;
+    }
+  }
+}
+</style>

+ 48 - 0
src/components/common/web/info/builds.vue

@@ -0,0 +1,48 @@
+<template>
+  <div id="builds">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <el-button type="success" plain @click="toBack()">返回</el-button>
+        </el-col>
+        <el-col :span="24" class="two">
+          <component :is="buildInfo" :info="info"></component>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+<script lang="ts" setup>
+import buildInfo from '@/components/common/build/info.vue';
+import type { Ref } from 'vue';
+import { ref, toRefs, onMounted } from 'vue';
+import { BuilddesireStore } from '@common/src/stores/studio/studios/builddesire';
+import type { IQueryResult } from '@/util/types.util';
+const builddesire = BuilddesireStore();
+const props = defineProps({
+  id: { type: String, default: () => '' },
+});
+const { id } = toRefs(props);
+let info: Ref<{}> = ref({});
+onMounted(async () => {
+  await search();
+});
+const search = async () => {
+  if (id.value) {
+    const res: IQueryResult = await builddesire.fetch(id.value);
+    info.value = res.data;
+  }
+};
+const emit = defineEmits(['toBack']);
+const toBack = () => {
+  emit('toBack', 'build');
+};
+</script>
+
+<style lang="scss" scoped>
+.main {
+  .one {
+    margin: 0 0 10px 0;
+  }
+}
+</style>

+ 48 - 0
src/components/common/web/info/demands.vue

@@ -0,0 +1,48 @@
+<template>
+  <div id="demands">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <el-button type="success" plain @click="toBack()">返回</el-button>
+        </el-col>
+        <el-col :span="24" class="two">
+          <component :is="demandInfo" :info="info"></component>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+<script lang="ts" setup>
+import demandInfo from '@/components/common/demand/info.vue';
+import type { Ref } from 'vue';
+import { ref, toRefs, onMounted } from 'vue';
+import { TecholdemandStore } from '@common/src/stores/studio/supplydemand/techoldemand';
+import type { IQueryResult } from '@/util/types.util';
+const techoldemand = TecholdemandStore();
+const props = defineProps({
+  id: { type: String, default: () => '' },
+});
+const { id } = toRefs(props);
+let info: Ref<{}> = ref({});
+onMounted(async () => {
+  await search();
+});
+const search = async () => {
+  if (id.value) {
+    const res: IQueryResult = await techoldemand.fetch(id.value);
+    info.value = res.data;
+  }
+};
+const emit = defineEmits(['toBack']);
+const toBack = () => {
+  emit('toBack', 'demand');
+};
+</script>
+
+<style lang="scss" scoped>
+.main {
+  .one {
+    margin: 0 0 10px 0;
+  }
+}
+</style>

+ 48 - 0
src/components/common/web/info/downloads.vue

@@ -0,0 +1,48 @@
+<template>
+  <div id="downloads">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <el-button type="success" plain @click="toBack()">返回</el-button>
+        </el-col>
+        <el-col :span="24" class="two">
+          <component :is="noticeInfo" :info="info"></component>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+<script lang="ts" setup>
+import noticeInfo from '@/components/common/notice/info.vue';
+import type { Ref } from 'vue';
+import { ref, toRefs, onMounted } from 'vue';
+import { RelevantdownloadStore } from '@common/src/stores/studio/other/relevantdownload';
+import type { IQueryResult } from '@/util/types.util';
+const relevantdownload = RelevantdownloadStore();
+const props = defineProps({
+  id: { type: String, default: () => '' },
+});
+const { id } = toRefs(props);
+let info: Ref<{}> = ref({});
+onMounted(async () => {
+  await search();
+});
+const search = async () => {
+  if (id.value) {
+    const res: IQueryResult = await relevantdownload.fetch(id.value);
+    info.value = res.data;
+  }
+};
+const emit = defineEmits(['toBack']);
+const toBack = () => {
+  emit('toBack', 'download');
+};
+</script>
+
+<style lang="scss" scoped>
+.main {
+  .one {
+    margin: 0 0 10px 0;
+  }
+}
+</style>

+ 48 - 0
src/components/common/web/info/notices.vue

@@ -0,0 +1,48 @@
+<template>
+  <div id="downloads">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <el-button type="success" plain @click="toBack()">返回</el-button>
+        </el-col>
+        <el-col :span="24" class="two">
+          <component :is="noticeInfo" :info="info"></component>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+<script lang="ts" setup>
+import noticeInfo from '@/components/common/notice/info.vue';
+import type { Ref } from 'vue';
+import { ref, toRefs, onMounted } from 'vue';
+import { NoticeStore } from '@common/src/stores/studio/other/notice';
+import type { IQueryResult } from '@/util/types.util';
+const notice = NoticeStore();
+const props = defineProps({
+  id: { type: String, default: () => '' },
+});
+const { id } = toRefs(props);
+let info: Ref<{}> = ref({});
+onMounted(async () => {
+  await search();
+});
+const search = async () => {
+  if (id.value) {
+    const res: IQueryResult = await notice.fetch(id.value);
+    info.value = res.data;
+  }
+};
+const emit = defineEmits(['toBack']);
+const toBack = () => {
+  emit('toBack', 'notice');
+};
+</script>
+
+<style lang="scss" scoped>
+.main {
+  .one {
+    margin: 0 0 10px 0;
+  }
+}
+</style>

+ 112 - 0
src/components/common/web/info/scientists.vue

@@ -0,0 +1,112 @@
+<template>
+  <div id="scientists">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <el-button type="success" plain @click="toBack()">返回</el-button>
+        </el-col>
+        <el-col :span="24" class="two">
+          <component
+            :is="scientistInfo"
+            :info="info"
+            :educationList="educationList"
+            :degreeList="degreeList"
+            :fieldList="fieldList"
+            :isjobList="isjobList"
+            :zcList="zcList"
+            type="web"
+          ></component>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+<script lang="ts" setup>
+import scientistInfo from '@/components/common/scientist/info.vue';
+import type { Ref } from 'vue';
+import { ref, toRefs, onMounted } from 'vue';
+import { UserStudioApplyStore } from '@common/src/stores/studio/role/userStudioApply';
+import { DictDataStore } from '@common/src/stores/users/sysdictdata'; // 字典表
+import type { IQueryResult } from '@/util/types.util';
+const sysdictdata = DictDataStore();
+const userStudioApply = UserStudioApplyStore();
+const props = defineProps({
+  id: { type: String, default: () => '' },
+});
+const { id } = toRefs(props);
+let info: Ref<{}> = ref({});
+// 行业领域
+let fieldList: Ref<any[]> = ref([]);
+// 是否在职人员
+let isjobList: Ref<any[]> = ref([]);
+
+let zcList: Ref<any[]> = ref([]);
+// 学历
+let educationList: Ref<any[]> = ref([]);
+// 学位
+let degreeList: Ref<any[]> = ref([]);
+onMounted(async () => {
+  await searchOther();
+  await search();
+});
+const search = async () => {
+  if (id.value) {
+    const res: IQueryResult = await userStudioApply.fetch(id.value);
+    let data: { is_job: any; zc: any; fields: any } = res.data as { is_job: any; zc: any; fields: any };
+    data.is_job = searchDictsis_job(data.is_job);
+    data.zc = searchDictszcList(data.zc);
+    if (data.fields && data.fields.length > 0) data.fields = searchDict(data.fields);
+    info.value = res.data;
+  }
+};
+const searchDict = (e) => {
+  let data = [];
+  if (e && e.length > 0) {
+    for (const val of e) {
+      let value = fieldList.value.find((r) => r.dict_value == val);
+      if (value) data.push(value.dict_label);
+    }
+    if (data && data.length > 0) return data.toString();
+  }
+};
+const searchDictsis_job = (e) => {
+  let data = isjobList.value.find((r) => r.dict_value == e);
+  if (data && data._id) return data.dict_label;
+};
+const searchDictszcList = (e) => {
+  let data = zcList.value.find((r) => r.dict_value == e);
+  if (data && data._id) return data.dict_label;
+};
+const emit = defineEmits(['toBack']);
+const toBack = () => {
+  emit('toBack', 'scientist');
+};
+// 查询其他信息
+const searchOther = async () => {
+  // 字典表---行业领域
+  const p1: IQueryResult = await sysdictdata.query({ dict_type: 'studio_field' });
+  fieldList.value = p1.data as [];
+  // 字典表---是否为在职人员
+  const p2: IQueryResult = await sysdictdata.query({ dict_type: 'studio_scientist_is_job' });
+  isjobList.value = p2.data as [];
+  // 字典表---专业技术职称
+  const p3: IQueryResult = await sysdictdata.query({ dict_type: 's-builddesire-zc' });
+  let data: any = p3.data as [];
+  data.filter((i) => i.dict_value != '0');
+  zcList.value = data;
+  // 字典表---学历
+  const p4: IQueryResult = await sysdictdata.query({ dict_type: 'education' });
+  educationList.value = p4.data as [];
+  // 字典表---学历
+  const p5: IQueryResult = await sysdictdata.query({ dict_type: 'degree' });
+  degreeList.value = p5.data as [];
+};
+</script>
+
+<style lang="scss" scoped>
+.main {
+  .one {
+    margin: 0 0 10px 0;
+  }
+}
+</style>

+ 61 - 0
src/components/common/web/info/studios.vue

@@ -0,0 +1,61 @@
+<template>
+  <div id="studios">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <el-button type="success" plain @click="toBack()">返回</el-button>
+        </el-col>
+        <el-col :span="24" class="two">
+          <component :is="studioInfo" :info="info" type="web"></component>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+<script setup lang="ts">
+import studioInfo from '@/components/common/studio/info.vue';
+import type { Ref } from 'vue';
+import { ref, onMounted, toRefs } from 'vue';
+import { StudioStore } from '@common/src/stores/studio/studios/studio'; // 列表
+import { ScientistsettleStore } from '@common/src/stores/studio/studios/scientistsettle';
+import type { IQueryResult } from '@/util/types.util';
+const scientistsettle = ScientistsettleStore();
+const studio = StudioStore();
+
+const props = defineProps({
+  id: { type: String, default: () => '' },
+});
+const { id } = toRefs(props);
+let info: Ref<{ team: any[] }> = ref({ team: [] });
+onMounted(async () => {
+  await search();
+});
+const search = async () => {
+  if (id.value) {
+    const res: IQueryResult = await studio.fetch(id.value);
+    info.value = res.data as { team: any };
+    await sarchTeam();
+  }
+};
+const sarchTeam = async () => {
+  let list = [];
+  let res = await scientistsettle.query({ studio_id: id.value });
+  if (res.total > 0) {
+    let data = res.data[0];
+    list = data.team;
+  }
+  info.value.team = list;
+};
+const emit = defineEmits(['toBack']);
+const toBack = () => {
+  emit('toBack', 'studio');
+};
+</script>
+
+<style lang="scss" scoped>
+.main {
+  .one {
+    margin: 0 0 10px 0;
+  }
+}
+</style>

+ 48 - 0
src/components/common/web/info/supports.vue

@@ -0,0 +1,48 @@
+<template>
+  <div id="supports">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <el-button type="success" plain @click="toBack()">返回</el-button>
+        </el-col>
+        <el-col :span="24" class="two">
+          <component :is="supportInfo" :info="info"></component>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+<script lang="ts" setup>
+import supportInfo from '@/components/common/support/info.vue';
+import type { Ref } from 'vue';
+import { ref, toRefs, onMounted } from 'vue';
+import { TecholsupportStore } from '@common/src/stores/studio/supplydemand/techolsupport';
+import type { IQueryResult } from '@/util/types.util';
+const techolsupport = TecholsupportStore();
+const props = defineProps({
+  id: { type: String, default: () => '' },
+});
+const { id } = toRefs(props);
+let info: Ref<{}> = ref({});
+onMounted(async () => {
+  await search();
+});
+const search = async () => {
+  if (id.value) {
+    const res: IQueryResult = await techolsupport.fetch(id.value);
+    info.value = res.data;
+  }
+};
+const emit = defineEmits(['toBack']);
+const toBack = () => {
+  emit('toBack', 'support');
+};
+</script>
+
+<style lang="scss" scoped>
+.main {
+  .one {
+    margin: 0 0 10px 0;
+  }
+}
+</style>

+ 85 - 0
src/components/common/web/info/units.vue

@@ -0,0 +1,85 @@
+<template>
+  <div id="units">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <el-button type="success" plain @click="toBack()">返回</el-button>
+        </el-col>
+        <el-col :span="24" class="two">
+          <component :is="unitInfo" :info="info" type="web"></component>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup lang="ts">
+import unitInfo from '@/components/common/unit/info.vue';
+import type { Ref } from 'vue';
+import { ref, toRefs, onMounted } from 'vue';
+import { UnitStudioApplyStore } from '@common/src/stores/studio/role/unitStudioApply'; // 列表
+import { DictDataStore } from '@common/src/stores/users/sysdictdata'; // 字典表
+import type { IQueryResult } from '@/util/types.util';
+const unitStudioApply = UnitStudioApplyStore();
+const sysdictdata = DictDataStore();
+const props = defineProps({
+  id: { type: String, default: () => '' },
+});
+const { id } = toRefs(props);
+let info: Ref<{}> = ref({});
+// 行业领域
+let fieldList: Ref<any[]> = ref([]);
+onMounted(async () => {
+  await searchOther();
+  await search();
+});
+const search = async () => {
+  if (id.value) {
+    const res: IQueryResult = await unitStudioApply.fetch(id.value);
+    let data: { fields: any } = res.data as { fields: any };
+    if (data.fields && data.fields.length > 0) data.fields = searchDict(data.fields);
+    info.value = res.data;
+  }
+};
+const searchDict = (e) => {
+  let data = [];
+  for (const val of e) {
+    let value = fieldList.value.find((r) => r.dict_value == val);
+    if (value) data.push(value.dict_label);
+  }
+  if (data && data.length > 0) return data.toString();
+  else return '暂无';
+};
+const emit = defineEmits(['toBack']);
+const toBack = () => {
+  emit('toBack', 'unit');
+};
+// 查询其他信息
+const searchOther = async () => {
+  // 字典表---行业领域
+  const p1: IQueryResult = await sysdictdata.query({ dict_type: 'studio_field' });
+  fieldList.value = p1.data as [];
+};
+</script>
+
+<style lang="scss" scoped>
+.main {
+  .one {
+    margin: 0 0 10px 0;
+  }
+  .two {
+    .direction {
+      display: inline-block;
+      background-color: #409eff;
+      border-radius: 5px;
+      padding: 0 5px;
+      margin: 0 5px 5px 0;
+      color: #ffffff;
+      line-height: 2.5;
+      span {
+        padding: 0 5px 0 0;
+      }
+    }
+  }
+}
+</style>

+ 156 - 0
src/components/common/web/list/build.vue

@@ -0,0 +1,156 @@
+<template>
+  <div id="build">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <component :is="partsSearch" :is_title="false" :is_search="true" :fields="fields" @search="partSearch">
+            <template #nature>
+              <el-option v-for="i in natureList" :key="i.model" :label="i.dict_label" :value="i.dict_value"></el-option>
+            </template>
+          </component>
+        </el-col>
+        <el-col :span="24" class="two">
+          <el-col :span="12" class="list" v-for="(item, index) in list" :key="index" @click="toView(item)">
+            <el-col :span="24" class="name">{{ item.company_name }}</el-col>
+            <el-col :span="24" class="other">
+              <el-col :span="8" class="other_1 textOver">
+                <span>单位性质:</span>
+                <span>{{ getDict(item.nature) }}</span>
+              </el-col>
+              <el-col :span="8" class="other_1 textOver">
+                <span>联系电话:</span>
+                <span>{{ item.phone }}</span>
+              </el-col>
+              <el-col :span="8" class="other_1 textOver">
+                <span>单位所在地:</span>
+                <span>{{ item.address }}</span>
+              </el-col>
+              <el-col :span="24" class="other_1 textOver">
+                <span>技术难题/战略发展问题:</span>
+                <span>{{ item.development }}</span>
+              </el-col>
+            </el-col>
+          </el-col>
+        </el-col>
+        <el-col :span="24" class="thr">
+          <component :is="CPage" :total="total" :limit="limit" @query="search"></component>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+<script lang="ts" setup>
+import CPage from '@/components/common/web/c-page.vue';
+import partsSearch from '@/components/c-search.vue';
+import type { Ref } from 'vue';
+import { ref, onMounted } from 'vue';
+import { DictDataStore } from '@common/src/stores/users/sysdictdata'; // 字典表
+import { BuilddesireStore } from '@common/src/stores/studio/studios/builddesire'; //
+import type { IQueryResult } from '@/util/types.util';
+const sysdictdata = DictDataStore();
+const builddesire = BuilddesireStore();
+let fields: Ref<any[]> = ref([
+  { label: '单位名称', model: 'company_name', isSearch: true },
+  { label: '单位性质', model: 'nature', type: 'select', isSearch: true },
+  { label: '联系电话', model: 'phone', isSearch: true },
+]);
+// 查询数据
+let searchForm: Ref<{}> = ref({});
+let list: Ref<any[]> = ref([]);
+// 总数
+let total: Ref<number> = ref(0);
+let limit: 8;
+let skip = 0;
+let natureList: Ref<any[]> = ref([]);
+onMounted(async () => {
+  await searchOther();
+  await search({ skip, limit });
+});
+// 查询
+const search = async (e: { skip: number; limit: number }) => {
+  const { skip, limit } = e;
+  let info = { limit: limit, skip: skip, ...searchForm.value, is_use: '0' };
+  if (info.limit == undefined) info.limit = 8;
+  const res: IQueryResult = await builddesire.query(info);
+  list.value = res.data as any[];
+  total.value = res.total;
+};
+// 查询
+const partSearch = (form: { [x: string]: any }) => {
+  searchForm.value = form;
+  search({ skip, limit });
+};
+const emit = defineEmits(['toView']);
+// 获取字典
+const getDict = (e: string) => {
+  let data = natureList.value.find((r) => r.dict_value == e);
+  if (data) return data.dict_label;
+  else return '暂无';
+};
+const toView = (e: object) => {
+  emit('toView', { data: e, component: 'builds' });
+};
+// 查询其他信息
+const searchOther = async () => {
+  // 字典表---单位性质
+  const p1: IQueryResult = await sysdictdata.query({ dict_type: 's-builddesire-nature' });
+  natureList.value = p1.data as [];
+};
+</script>
+
+<style lang="scss" scoped>
+.main {
+  .one {
+    box-shadow: 0 0 2px #858585;
+    padding: 10px;
+    margin: 0 0 10px 0;
+  }
+  .two {
+    display: flex;
+    flex-direction: row;
+    flex-wrap: wrap;
+    box-shadow: 0 0 5px #858585;
+    padding: 10px;
+    border-radius: 5px;
+    margin: 0 0 10px 0;
+    .list {
+      max-width: 49%;
+      border: 3px solid #a2e1f7;
+      padding: 10px;
+      border-radius: 5px;
+      margin: 0 20px 20px 0;
+      .name {
+        font-size: 20px;
+        font-family: cursive;
+        margin: 0 0 10px 0;
+        font-weight: bold;
+      }
+      .other {
+        display: flex;
+        flex-direction: row;
+        flex-wrap: wrap;
+        .other_1 {
+          margin: 0 0 10px 0;
+          span {
+            font-size: 14px;
+            color: #858585;
+          }
+          span:nth-child(2) {
+            color: #000000;
+          }
+        }
+      }
+    }
+    .list:hover {
+      cursor: pointer;
+      border: 3px solid #65cd94;
+      .name {
+        color: #ffffff;
+      }
+    }
+    .list:nth-child(2n) {
+      margin: 0 0 20px 0;
+    }
+  }
+}
+</style>

+ 153 - 0
src/components/common/web/list/demand.vue

@@ -0,0 +1,153 @@
+<template>
+  <div id="demand">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <component :is="partsSearch" :is_title="false" :is_search="true" :fields="fields" @search="partSearch"> </component>
+        </el-col>
+        <el-col :span="24" class="two">
+          <el-col class="list" :span="12" v-for="(item, index) in list" :key="index" @click="toView(item)">
+            <el-col :span="24" class="company">{{ item.title }}</el-col>
+            <el-col :span="24" class="other">
+              <el-col :span="8" class="other_1 textOver">
+                <span>依托单位名称:</span>
+                <span>{{ item.company_name }}</span>
+              </el-col>
+              <el-col :span="8" class="other_1 textOver">
+                <span>需求截止时间:</span>
+                <span>{{ item.stop_date }}</span>
+              </el-col>
+              <el-col :span="8" class="other_1 textOver">
+                <span>专业领域:</span>
+                <span>{{ getDict(item.fields) }}</span>
+              </el-col>
+            </el-col>
+          </el-col>
+        </el-col>
+        <el-col :span="24" class="thr">
+          <component :is="CPage" :total="total" :limit="limit" @query="search"></component>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+<script lang="ts" setup>
+import CPage from '@/components/common/web/c-page.vue';
+import partsSearch from '@/components/c-search.vue';
+import type { Ref } from 'vue';
+import { ref, onMounted } from 'vue';
+import { DictDataStore } from '@common/src/stores/users/sysdictdata'; // 字典表
+import { TecholdemandStore } from '@common/src/stores/studio/supplydemand/techoldemand'; //
+import type { IQueryResult } from '@/util/types.util';
+const sysdictdata = DictDataStore();
+const techoldemand = TecholdemandStore();
+let fields: Ref<any[]> = ref([
+  { label: '标题', model: 'title', isSearch: true },
+  { label: '依托单位名称', model: 'scientist_name', isSearch: true },
+  { label: '科学家名称', model: 'scientist_name', isSearch: true },
+]);
+// 查询数据
+let searchForm: Ref<{}> = ref({});
+let list: Ref<any[]> = ref([]);
+// 总数
+let total: Ref<number> = ref(0);
+let limit: 10;
+let skip = 0;
+let fieldList: Ref<any[]> = ref([]);
+onMounted(async () => {
+  await searchOther();
+  await search({ skip, limit });
+});
+// 查询
+const search = async (e: { skip: number; limit: number }) => {
+  const { skip, limit } = e;
+  let info = { limit: limit, skip: skip, ...searchForm.value, is_use: '0', status: '1' };
+  if (info.limit == undefined) info.limit = 8;
+  const res: IQueryResult = await techoldemand.query(info);
+  list.value = res.data as any[];
+  total.value = res.total;
+};
+// 查询
+const partSearch = (form: { [x: string]: any }) => {
+  searchForm.value = form;
+  search({ skip, limit });
+};
+const emit = defineEmits(['toView']);
+//获取领域信息
+const getDict = (e: any) => {
+  let fields = [];
+  for (const val of e) {
+    let data = fieldList.value.find((i) => i.dict_value == val);
+    if (data) fields.push(data.dict_label);
+  }
+  let data = fields.join(',');
+  return data;
+};
+const toView = (e: object) => {
+  emit('toView', { data: e, component: 'demands' });
+};
+// 查询其他信息
+const searchOther = async () => {
+  // 字典表---单位性质
+  const p1: IQueryResult = await sysdictdata.query({ dict_type: 'studio_field' });
+  fieldList.value = p1.data as [];
+};
+</script>
+
+<style lang="scss" scoped>
+.main {
+  .one {
+    box-shadow: 0 0 2px #858585;
+    padding: 10px;
+    margin: 0 0 10px 0;
+  }
+  .two {
+    display: flex;
+    flex-direction: row;
+    flex-wrap: wrap;
+    box-shadow: 0 0 5px #858585;
+    padding: 10px;
+    border-radius: 5px;
+    margin: 0 0 10px 0;
+    .list {
+      max-width: 49%;
+      border: 3px solid #a2e1f7;
+      padding: 10px;
+      border-radius: 5px;
+      margin: 0 20px 20px 0;
+      .company {
+        font-size: 20px;
+        font-family: cursive;
+        margin: 0 0 10px 0;
+        font-weight: bold;
+      }
+      .other {
+        display: flex;
+        flex-direction: row;
+        flex-wrap: wrap;
+
+        .other_1 {
+          margin: 0 0 10px 0;
+          span {
+            font-size: 14px;
+            color: #858585;
+          }
+          span:nth-child(2) {
+            color: #000000;
+          }
+        }
+      }
+    }
+    .list:hover {
+      cursor: pointer;
+      border: 3px solid #65cd94;
+      .company {
+        color: #ffffff;
+      }
+    }
+    .list:nth-child(2n) {
+      margin: 0 0 20px 0;
+    }
+  }
+}
+</style>

+ 103 - 0
src/components/common/web/list/download.vue

@@ -0,0 +1,103 @@
+<template>
+  <div id="support">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <component :is="partsSearch" :is_title="false" :is_search="true" :fields="fields" @search="partSearch"> </component>
+        </el-col>
+        <el-col :span="24" class="two">
+          <el-col class="list" :span="12" v-for="(item, index) in list" :key="index" @click="toView(item)">
+            <el-col :span="20" class="title">{{ item.title }}</el-col>
+            <el-col :span="4" class="other">{{ item.date }} </el-col>
+          </el-col>
+        </el-col>
+        <el-col :span="24" class="thr">
+          <component :is="CPage" :total="total" :limit="limit" @query="search"></component>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+<script lang="ts" setup>
+import CPage from '@/components/common/web/c-page.vue';
+import partsSearch from '@/components/c-search.vue';
+import type { Ref } from 'vue';
+import { ref, onMounted } from 'vue';
+import { RelevantdownloadStore } from '@common/src/stores/studio/other/relevantdownload';
+import type { IQueryResult } from '@/util/types.util';
+const relevantdownload = RelevantdownloadStore();
+let fields: Ref<any[]> = ref([{ label: '标题', model: 'title', isSearch: true }]);
+// 查询数据
+let searchForm: Ref<{}> = ref({});
+let list: Ref<any[]> = ref([]);
+// 总数
+let total: Ref<number> = ref(0);
+let limit: 16;
+let skip = 0;
+onMounted(async () => {
+  await search({ skip, limit });
+});
+// 查询
+const search = async (e: { skip: number; limit: number }) => {
+  const { skip, limit } = e;
+  let info = { limit: limit, skip: skip, ...searchForm.value };
+  if (info.limit == undefined) info.limit = 8;
+  const res: IQueryResult = await relevantdownload.query(info);
+  list.value = res.data as any[];
+  total.value = res.total;
+};
+// 查询
+const partSearch = (form: { [x: string]: any }) => {
+  searchForm.value = form;
+  search({ skip, limit });
+};
+const emit = defineEmits(['toView']);
+const toView = (e: object) => {
+  emit('toView', { data: e, component: 'downloads' });
+};
+</script>
+
+<style lang="scss" scoped>
+.main {
+  .one {
+    box-shadow: 0 0 2px #858585;
+    padding: 10px;
+    margin: 0 0 10px 0;
+  }
+  .two {
+    display: flex;
+    flex-direction: row;
+    flex-wrap: wrap;
+    box-shadow: 0 0 5px #858585;
+    padding: 10px;
+    border-radius: 5px;
+    margin: 0 0 10px 0;
+    .list {
+      max-width: 49%;
+      border-bottom: 3px dashed #a2e1f7;
+      padding: 12px 10px;
+      margin: 0 20px 20px 0;
+      .title {
+        font-size: 20px;
+        font-family: cursive;
+        font-weight: bold;
+      }
+      .other {
+        font-size: 14px;
+        color: #858585;
+        text-align: right;
+      }
+    }
+    .list:hover {
+      cursor: pointer;
+      border-bottom: 3px dashed #65cd94;
+      .title {
+        color: #ffffff;
+      }
+    }
+    .list:nth-child(2n) {
+      margin: 0 0 20px 0;
+    }
+  }
+}
+</style>

+ 130 - 0
src/components/common/web/list/notice.vue

@@ -0,0 +1,130 @@
+<template>
+  <div id="support">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <component :is="partsSearch" :is_title="false" :is_search="true" :fields="fields" @search="partSearch"> </component>
+        </el-col>
+        <el-col :span="24" class="two">
+          <el-col class="list" :span="12" v-for="(item, index) in list" :key="index" @click="toView(item)">
+            <el-col :span="24" class="title">{{ item.title }}</el-col>
+            <el-col :span="24" class="other">
+              <el-col :span="8" class="other_1 textOver">
+                <span>发布时间:</span>
+                <span>{{ item.date }}</span>
+              </el-col>
+              <el-col :span="8" class="other_1 textOver">
+                <span>来源:</span>
+                <span>{{ item.origin }}</span>
+              </el-col>
+            </el-col>
+          </el-col>
+        </el-col>
+        <el-col :span="24" class="thr">
+          <component :is="CPage" :total="total" :limit="limit" @query="search"></component>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+<script lang="ts" setup>
+import CPage from '@/components/common/web/c-page.vue';
+import partsSearch from '@/components/c-search.vue';
+import type { Ref } from 'vue';
+import { ref, onMounted } from 'vue';
+import { NoticeStore } from '@common/src/stores/studio/other/notice'; //
+import type { IQueryResult } from '@/util/types.util';
+const notice = NoticeStore();
+let fields: Ref<any[]> = ref([
+  { label: '标题', model: 'title', isSearch: true },
+  { label: '来源', model: 'origin', isSearch: true },
+]);
+// 查询数据
+let searchForm: Ref<{}> = ref({});
+let list: Ref<any[]> = ref([]);
+// 总数
+let total: Ref<number> = ref(0);
+let limit: 10;
+let skip = 0;
+
+onMounted(async () => {
+  await search({ skip, limit });
+});
+// 查询
+const search = async (e: { skip: number; limit: number }) => {
+  const { skip, limit } = e;
+  let info = { limit: limit, skip: skip, ...searchForm.value, status: '1' };
+  if (info.limit == undefined) info.limit = 8;
+  const res: IQueryResult = await notice.query(info);
+  list.value = res.data as any[];
+  total.value = res.total;
+};
+// 查询
+const partSearch = (form: { [x: string]: any }) => {
+  searchForm.value = form;
+  search({ skip, limit });
+};
+const emit = defineEmits(['toView']);
+
+const toView = (e: object) => {
+  emit('toView', { data: e, component: 'notices' });
+};
+</script>
+
+<style lang="scss" scoped>
+.main {
+  .one {
+    box-shadow: 0 0 2px #858585;
+    padding: 10px;
+    margin: 0 0 10px 0;
+  }
+  .two {
+    display: flex;
+    flex-direction: row;
+    flex-wrap: wrap;
+    box-shadow: 0 0 5px #858585;
+    padding: 10px;
+    border-radius: 5px;
+    margin: 0 0 10px 0;
+    .list {
+      max-width: 49%;
+      border: 3px solid #a2e1f7;
+      padding: 10px;
+      border-radius: 5px;
+      margin: 0 20px 20px 0;
+      .title {
+        font-size: 20px;
+        font-family: cursive;
+        margin: 0 0 10px 0;
+        font-weight: bold;
+      }
+      .other {
+        display: flex;
+        flex-direction: row;
+        flex-wrap: wrap;
+
+        .other_1 {
+          margin: 0 0 10px 0;
+          span {
+            font-size: 14px;
+            color: #858585;
+          }
+          span:nth-child(2) {
+            color: #000000;
+          }
+        }
+      }
+    }
+    .list:hover {
+      cursor: pointer;
+      border: 3px solid #65cd94;
+      .title {
+        color: #ffffff;
+      }
+    }
+    .list:nth-child(2n) {
+      margin: 0 0 20px 0;
+    }
+  }
+}
+</style>

+ 181 - 0
src/components/common/web/list/scientist.vue

@@ -0,0 +1,181 @@
+<template>
+  <div id="unit">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <component :is="partsSearch" :is_title="false" :is_search="true" :fields="fields" @search="partSearch">
+            <template #fields>
+              <el-option v-for="i in fieldList" :key="i.model" :label="i.dict_label" :value="i.dict_value"></el-option>
+            </template>
+          </component>
+        </el-col>
+        <el-col :span="24" class="two">
+          <el-col class="list" :span="12" v-for="(item, index) in list" :key="index" @click="toView(item)">
+            <el-col :span="24" class="name">{{ item.name }}</el-col>
+            <el-col :span="24" class="other">
+              <el-col :span="12" class="other_1 textOver">
+                <span>专业技术职称:</span>
+                <span>{{ getDict(item.zc) }}</span>
+              </el-col>
+              <el-col :span="12" class="other_1 textOver">
+                <span>单位名称:</span>
+                <span>{{ item.company }}</span>
+              </el-col>
+              <el-col :span="12" class="other_1 textOver">
+                <span>研究领域:</span>
+                <span class="direction" v-for="(i, index) in item.fields" :key="index">{{ i.name }};</span>
+              </el-col>
+              <el-col :span="12" class="other_1 textOver">
+                <span>研究方向:</span>
+                <span class="direction" v-for="(p, index) in item.direction" :key="index">{{ p.name }}; </span>
+              </el-col>
+            </el-col>
+          </el-col>
+        </el-col>
+        <el-col :span="24" class="thr">
+          <component :is="CPage" :total="total" :limit="limit" @query="search"></component>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+<script lang="ts" setup>
+import CPage from '@/components/common/web/c-page.vue';
+import partsSearch from '@/components/c-search.vue';
+import type { Ref } from 'vue';
+import { ref, onMounted } from 'vue';
+import { DictDataStore } from '@common/src/stores/users/sysdictdata'; // 字典表
+import { UserStudioApplyStore } from '@common/src/stores/studio/role/userStudioApply'; //
+import type { IQueryResult } from '@/util/types.util';
+const sysdictdata = DictDataStore();
+const userStudioApply = UserStudioApplyStore();
+let fields: Ref<any[]> = ref([
+  { label: '姓名', model: 'name', isSearch: true },
+  { label: '单位名称', model: 'company', isSearch: true },
+  { label: '研究领域', model: 'fields', type: 'select', isSearch: true },
+  { label: '研究方向', model: 'direction', isSearch: true },
+]);
+// 查询数据
+let searchForm: Ref<{}> = ref({});
+let list: Ref<any[]> = ref([]);
+// 总数
+let total: Ref<number> = ref(0);
+let limit: 10;
+let skip = 0;
+let fieldList: Ref<any[]> = ref([]);
+// 专业技术职称
+let zcList: Ref<any[]> = ref([]);
+onMounted(async () => {
+  await searchOther();
+  await search({ skip, limit });
+});
+// 查询
+const search = async (e: { skip: number; limit: number }) => {
+  const { skip, limit } = e;
+  let info = { limit: limit, skip: skip, ...searchForm.value, is_use: '0', status: '1' };
+  if (info.limit == undefined) info.limit = 8;
+  const res: IQueryResult = await userStudioApply.query(info);
+  list.value = res.data as any[];
+  let p1: any = res.data as any[];
+  for (const val of p1) {
+    if (val.fields) val.fields = searchDict(val.fields);
+  }
+  total.value = res.total;
+};
+// 查询
+const partSearch = (form: { [x: string]: any }) => {
+  searchForm.value = form;
+  search({ skip, limit });
+};
+const emit = defineEmits(['toView']);
+//获取领域信息
+const searchDict = (fields: any) => {
+  let data = [];
+  for (const val of fields) {
+    let info = fieldList.value.find((i) => i.dict_value == val);
+    if (info) data.push({ name: info.dict_label });
+  }
+  return data;
+};
+const getDict = (e: string) => {
+  let data = zcList.value.find((i) => i.dict_value == e);
+  if (data) return data.dict_label;
+  else return '暂无';
+};
+
+const toView = (e: object) => {
+  emit('toView', { data: e, component: 'scientists' });
+};
+// 查询其他信息
+const searchOther = async () => {
+  // 字典表---单位性质
+  const p1: IQueryResult = await sysdictdata.query({ dict_type: 'studio_field' });
+  fieldList.value = p1.data as [];
+  // 字典表---专业技术职称
+  const p2: IQueryResult = await sysdictdata.query({ dict_type: 's-builddesire-zc' });
+  let data: any = p2.data as [];
+  data.filter((i) => i.dict_value != '0');
+  zcList.value = data;
+};
+</script>
+
+<style lang="scss" scoped>
+.main {
+  .one {
+    box-shadow: 0 0 2px #858585;
+    padding: 10px;
+    margin: 0 0 10px 0;
+  }
+  .two {
+    display: flex;
+    flex-direction: row;
+    flex-wrap: wrap;
+    box-shadow: 0 0 5px #858585;
+    padding: 10px;
+    border-radius: 5px;
+    margin: 0 0 10px 0;
+    .list {
+      max-width: 49%;
+      border: 3px solid #a2e1f7;
+      padding: 10px;
+      border-radius: 5px;
+      margin: 0 20px 10px 0;
+      .name {
+        font-size: 20px;
+        font-family: cursive;
+        margin: 0 0 10px 0;
+        font-weight: bold;
+      }
+      .other {
+        display: flex;
+        flex-direction: row;
+        flex-wrap: wrap;
+
+        .other_1 {
+          margin: 0 0 10px 0;
+          span {
+            font-size: 14px;
+            color: #858585;
+          }
+          span:nth-child(2) {
+            color: #000000;
+          }
+          .direction {
+            color: #000000;
+          }
+        }
+      }
+    }
+    .list:hover {
+      cursor: pointer;
+      border: 3px solid #65cd94;
+      .name {
+        color: #ffffff;
+      }
+    }
+    .list:nth-child(2n) {
+      margin: 0 0 10px 0;
+    }
+  }
+}
+</style>

+ 134 - 0
src/components/common/web/list/studio.vue

@@ -0,0 +1,134 @@
+<template>
+  <div id="studio">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <component :is="partsSearch" :is_title="false" :is_search="true" :fields="fields" @search="partSearch"> </component>
+        </el-col>
+        <el-col :span="24" class="two">
+          <el-col class="list" :span="6" v-for="(item, index) in list" :key="index" @click="toView(item)">
+            <el-col :span="24" class="name">{{ item.name }}</el-col>
+            <el-col :span="24" class="other">
+              <el-col :span="24" class="other_1">
+                <span>依托单位:</span>
+                <span>{{ item.company_name }}</span>
+              </el-col>
+              <el-col :span="24" class="other_1">
+                <span>入驻科学家:</span>
+                <span>{{ item.scientist_name }}</span>
+              </el-col>
+            </el-col>
+          </el-col>
+        </el-col>
+        <el-col :span="24" class="thr">
+          <component :is="CPage" :total="total" :limit="limit" @query="search"></component>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+<script lang="ts" setup>
+import CPage from '@/components/common/web/c-page.vue';
+import partsSearch from '@/components/c-search.vue';
+import type { Ref } from 'vue';
+import { ref, onMounted } from 'vue';
+import { StudioStore } from '@common/src/stores/studio/studios/studio'; //
+import type { IQueryResult } from '@/util/types.util';
+const studio = StudioStore();
+let fields: Ref<any[]> = ref([
+  { label: '工作室名称', model: 'name', isSearch: true },
+  { label: '依托单位', model: 'company_name', isSearch: true },
+  { label: '入驻科学家', model: 'scientist_name', isSearch: true },
+]);
+// 查询数据
+let searchForm: Ref<{}> = ref({});
+let list: Ref<any[]> = ref([]);
+// 总数
+let total: Ref<number> = ref(0);
+let limit: 8;
+let skip = 0;
+onMounted(async () => {
+  await search({ skip, limit });
+});
+// 查询
+const search = async (e: { skip: number; limit: number }) => {
+  const { skip, limit } = e;
+  let info = { limit: limit, skip: skip, ...searchForm.value, status: '1' };
+  if (info.limit == undefined) info.limit = 8;
+  const res: IQueryResult = await studio.query(info);
+  list.value = res.data as any[];
+  total.value = res.total;
+};
+// 查询
+const partSearch = (form: { [x: string]: any }) => {
+  searchForm.value = form;
+  search({ skip, limit });
+};
+const emit = defineEmits(['toView']);
+
+const toView = (e: object) => {
+  emit('toView', { data: e, component: 'studios' });
+};
+</script>
+
+<style lang="scss" scoped>
+.main {
+  .one {
+    box-shadow: 0 0 2px #858585;
+    padding: 10px;
+    margin: 0 0 10px 0;
+  }
+  .two {
+    display: flex;
+    flex-direction: row;
+    flex-wrap: wrap;
+    box-shadow: 0 0 5px #858585;
+    padding: 10px;
+    border-radius: 5px;
+    margin: 0 0 10px 0;
+    .list {
+      max-width: 22%;
+      min-height: 270px;
+      overflow: hidden;
+      border: 3px solid #a2e1f7;
+      padding: 10px;
+      border-radius: 5px;
+      margin: 0 40px 10px 0;
+      .name {
+        text-align: center;
+        font-size: 25px;
+        font-family: cursive;
+        margin: 0 0 5px 0;
+        padding: 10px 0;
+        font-weight: bold;
+      }
+      .other {
+        display: flex;
+        flex-direction: row;
+        flex-wrap: wrap;
+
+        .other_1 {
+          margin: 0 0 5px 0;
+          span {
+            font-size: 14px;
+            color: #858585;
+          }
+          span:nth-child(2) {
+            color: #000000;
+          }
+        }
+      }
+    }
+    .list:hover {
+      cursor: pointer;
+      border: 3px solid #65cd94;
+      .name {
+        color: #ffffff;
+      }
+    }
+    .list:nth-child(4n) {
+      margin: 0 0 10px 0;
+    }
+  }
+}
+</style>

+ 154 - 0
src/components/common/web/list/support.vue

@@ -0,0 +1,154 @@
+<template>
+  <div id="support">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <component :is="partsSearch" :is_title="false" :is_search="true" :fields="fields" @search="partSearch"> </component>
+        </el-col>
+        <el-col :span="24" class="two">
+          <el-col class="list" :span="12" v-for="(item, index) in list" :key="index" @click="toView(item)">
+            <el-col :span="24" class="company">{{ item.title }}</el-col>
+            <el-col :span="24" class="other">
+              <el-col :span="8" class="other_1 textOver">
+                <span>科学家姓名:</span>
+                <span>{{ item.scientist_name }}</span>
+              </el-col>
+              <el-col :span="8" class="other_1 textOver">
+                <span>单位名称:</span>
+                <span>{{ item.company_name }}</span>
+              </el-col>
+              <el-col :span="8" class="other_1 textOver">
+                <span>行业领域:</span>
+                <span>{{ getDict(item.fields) }}</span>
+              </el-col>
+            </el-col>
+          </el-col>
+        </el-col>
+        <el-col :span="24" class="thr">
+          <component :is="CPage" :total="total" :limit="limit" @query="search"></component>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+<script lang="ts" setup>
+import CPage from '@/components/common/web/c-page.vue';
+import partsSearch from '@/components/c-search.vue';
+import type { Ref } from 'vue';
+import { ref, onMounted } from 'vue';
+import { DictDataStore } from '@common/src/stores/users/sysdictdata'; // 字典表
+import { TecholsupportStore } from '@common/src/stores/studio/supplydemand/techolsupport'; //
+import type { IQueryResult } from '@/util/types.util';
+const sysdictdata = DictDataStore();
+const techolsupport = TecholsupportStore();
+let fields: Ref<any[]> = ref([
+  { label: '标题', model: 'title', isSearch: true },
+  { label: '科学家姓名', model: 'scientist_name', isSearch: true },
+  { label: '单位名称', model: 'company_name', isSearch: true },
+]);
+// 查询数据
+let searchForm: Ref<{}> = ref({});
+let list: Ref<any[]> = ref([]);
+// 总数
+let total: Ref<number> = ref(0);
+let limit: 10;
+let skip = 0;
+let fieldList: Ref<any[]> = ref([]);
+onMounted(async () => {
+  await searchOther();
+  await search({ skip, limit });
+});
+// 查询
+const search = async (e: { skip: number; limit: number }) => {
+  const { skip, limit } = e;
+  let info = { limit: limit, skip: skip, ...searchForm.value, is_use: '0', status: '1' };
+  if (info.limit == undefined) info.limit = 8;
+  const res: IQueryResult = await techolsupport.query(info);
+  list.value = res.data as any[];
+  total.value = res.total;
+};
+// 查询
+const partSearch = (form: { [x: string]: any }) => {
+  searchForm.value = form;
+  search({ skip, limit });
+};
+const emit = defineEmits(['toView']);
+
+const getDict = (e: any) => {
+  let fields = [];
+  for (const val of e) {
+    let data = fieldList.value.find((i) => i.dict_value == val);
+    if (data) fields.push(data.dict_label);
+  }
+  let data = fields.join(',');
+  return data;
+};
+
+const toView = (e: object) => {
+  emit('toView', { data: e, component: 'supports' });
+};
+// 查询其他信息
+const searchOther = async () => {
+  // 字典表---单位性质
+  const p1: IQueryResult = await sysdictdata.query({ dict_type: 'studio_field' });
+  fieldList.value = p1.data as [];
+};
+</script>
+
+<style lang="scss" scoped>
+.main {
+  .one {
+    box-shadow: 0 0 2px #858585;
+    padding: 10px;
+    margin: 0 0 10px 0;
+  }
+  .two {
+    display: flex;
+    flex-direction: row;
+    flex-wrap: wrap;
+    box-shadow: 0 0 5px #858585;
+    padding: 10px;
+    border-radius: 5px;
+    margin: 0 0 10px 0;
+    .list {
+      max-width: 49%;
+      border: 3px solid #a2e1f7;
+      padding: 10px;
+      border-radius: 5px;
+      margin: 0 20px 20px 0;
+      .company {
+        font-size: 20px;
+        font-family: cursive;
+        margin: 0 0 10px 0;
+        font-weight: bold;
+      }
+      .other {
+        display: flex;
+        flex-direction: row;
+        flex-wrap: wrap;
+
+        .other_1 {
+          margin: 0 0 10px 0;
+          span {
+            font-size: 14px;
+            color: #858585;
+          }
+          span:nth-child(2) {
+            color: #000000;
+          }
+        }
+      }
+    }
+    .list:hover {
+      cursor: pointer;
+      border: 3px solid #65cd94;
+      .company {
+        color: #ffffff;
+      }
+    }
+    .list:nth-child(2n) {
+      margin: 0 0 20px 0;
+    }
+  }
+}
+</style>

+ 168 - 0
src/components/common/web/list/unit.vue

@@ -0,0 +1,168 @@
+<template>
+  <div id="unit">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <component :is="partsSearch" :is_title="false" :is_search="true" :fields="fields" @search="partSearch">
+            <template #fields>
+              <el-option v-for="i in fieldList" :key="i.model" :label="i.dict_label" :value="i.dict_value"></el-option>
+            </template>
+          </component>
+        </el-col>
+        <el-col :span="24" class="two">
+          <el-col class="list" :span="12" v-for="(item, index) in list" :key="index" @click="toView(item)">
+            <el-col :span="24" class="company">{{ item.company }}</el-col>
+            <el-col :span="24" class="other">
+              <el-col :span="12" class="other_1 textOver">
+                <span>单位联系人:</span>
+                <span>{{ item.unit_contact }}</span>
+              </el-col>
+              <el-col :span="12" class="other_1 textOver">
+                <span>单位地址:</span>
+                <span>{{ item.address }}</span>
+              </el-col>
+              <el-col :span="12" class="other_1 textOver">
+                <span>行业领域:</span>
+                <span class="direction" v-for="(i, index) in item.fields" :key="index">{{ i.name }};</span>
+              </el-col>
+              <el-col :span="12" class="other_1 textOver">
+                <span>技术需求方向:</span>
+                <span class="direction" v-for="(p, index) in item.direction" :key="index">{{ p.name }}; </span>
+              </el-col>
+            </el-col>
+          </el-col>
+        </el-col>
+        <el-col :span="24" class="thr">
+          <component :is="CPage" :total="total" :limit="limit" @query="search"></component>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+<script lang="ts" setup>
+import CPage from '@/components/common/web/c-page.vue';
+import partsSearch from '@/components/c-search.vue';
+import type { Ref } from 'vue';
+import { ref, onMounted } from 'vue';
+import { DictDataStore } from '@common/src/stores/users/sysdictdata'; // 字典表
+import { UnitStudioApplyStore } from '@common/src/stores/studio/role/unitStudioApply'; //
+import type { IQueryResult } from '@/util/types.util';
+const sysdictdata = DictDataStore();
+const unitStudioApply = UnitStudioApplyStore();
+let fields: Ref<any[]> = ref([
+  { label: '单位名称', model: 'company', isSearch: true },
+  // { label: '单位地址', model: 'address', isSearch: true },
+  { label: '行业领域', model: 'fields', type: 'select', isSearch: true },
+  { label: '技术需求方向', model: 'direction', isSearch: true },
+]);
+// 查询数据
+let searchForm: Ref<{}> = ref({});
+let list: Ref<any[]> = ref([]);
+// 总数
+let total: Ref<number> = ref(0);
+let limit: 10;
+let skip = 0;
+let fieldList: Ref<any[]> = ref([]);
+onMounted(async () => {
+  await searchOther();
+  await search({ skip, limit });
+});
+// 查询
+const search = async (e: { skip: number; limit: number }) => {
+  const { skip, limit } = e;
+  let info = { limit: limit, skip: skip, ...searchForm.value, is_use: '0', status: '1' };
+  if (info.limit == undefined) info.limit = 8;
+  const res: IQueryResult = await unitStudioApply.query(info);
+  list.value = res.data as any[];
+  let p1: any = res.data as any[];
+  for (const val of p1) {
+    if (val.fields) val.fields = getDict(val.fields);
+  }
+  total.value = res.total;
+};
+// 查询
+const partSearch = (form: { [x: string]: any }) => {
+  searchForm.value = form;
+  search({ skip, limit });
+};
+const emit = defineEmits(['toView']);
+//获取领域信息
+const getDict = (fields: any) => {
+  let data = [];
+  for (const val of fields) {
+    let info = fieldList.value.find((i) => i.dict_value == val);
+    if (info) data.push({ name: info.dict_label });
+  }
+  return data;
+};
+const toView = (e: object) => {
+  emit('toView', { data: e, component: 'units' });
+};
+// 查询其他信息
+const searchOther = async () => {
+  // 字典表---单位性质
+  const p1: IQueryResult = await sysdictdata.query({ dict_type: 'studio_field' });
+  fieldList.value = p1.data as [];
+};
+</script>
+
+<style lang="scss" scoped>
+.main {
+  .one {
+    box-shadow: 0 0 2px #858585;
+    padding: 10px;
+    margin: 0 0 10px 0;
+  }
+  .two {
+    display: flex;
+    flex-direction: row;
+    flex-wrap: wrap;
+    box-shadow: 0 0 5px #858585;
+    padding: 10px;
+    border-radius: 5px;
+    margin: 0 0 10px 0;
+    .list {
+      max-width: 49%;
+      border: 3px solid #a2e1f7;
+      padding: 10px;
+      border-radius: 5px;
+      margin: 0 20px 10px 0;
+      .company {
+        font-size: 20px;
+        font-family: cursive;
+        margin: 0 0 10px 0;
+        font-weight: bold;
+      }
+      .other {
+        display: flex;
+        flex-direction: row;
+        flex-wrap: wrap;
+
+        .other_1 {
+          margin: 0 0 10px 0;
+          span {
+            font-size: 14px;
+            color: #858585;
+          }
+          span:nth-child(2) {
+            color: #000000;
+          }
+          .direction {
+            color: #000000;
+          }
+        }
+      }
+    }
+    .list:hover {
+      cursor: pointer;
+      border: 3px solid #65cd94;
+      .company {
+        color: #ffffff;
+      }
+    }
+    .list:nth-child(2n) {
+      margin: 0 0 10px 0;
+    }
+  }
+}
+</style>

+ 1 - 1
src/views/center/studio/info/info.vue

@@ -19,7 +19,7 @@ import { useRoute } from 'vue-router';
 import type { Ref } from 'vue';
 import { ref, onMounted } from 'vue';
 import { StudioStore } from '@common/src/stores/studio/studios/studio'; // 列表
-import { ScientistsettleStore } from '@common/src/stores/studio/studios/scientistsettle'; // 字典表
+import { ScientistsettleStore } from '@common/src/stores/studio/studios/scientistsettle'; 
 import type { IQueryResult } from '@/util/types.util';
 const scientistsettle = ScientistsettleStore();
 const studio = StudioStore();