index.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. <template>
  2. <!-- <el-card class="workspace-info card-border mb-2">
  3. <div class="workspace-name">
  4. <div class="card-header">
  5. <span>{{ form.name }}</span>
  6. </div>
  7. </div>
  8. </el-card> -->
  9. <div class="flex" v-loading="loading">
  10. <el-card class="workspace-info w-full" shadow="always" style="padding-bottom: 40px;">
  11. <template #header>
  12. <div class="card-header" style="display: flex; align-items: center; justify-content: space-between;">
  13. <span style="flex-grow: 1; text-align: center;font-weight: bold;">工作间信息</span>
  14. <div class="pull-right">
  15. <el-button type="primary" @click="openDialog">修改</el-button>
  16. </div>
  17. </div>
  18. </template>
  19. <ul class="user-info">
  20. <div class="info-row">
  21. <li class="info-item">
  22. <Icon class="mr-5px" icon="ep:bell" />
  23. <span class="info-label">工作间名称:</span>
  24. <span class="pull-right">{{ userInfo.name }}</span>
  25. </li>
  26. <li class="info-item">
  27. <Icon class="mr-5px" icon="ep:phone" />
  28. <span class="info-label">联系电话:</span>
  29. <span class="pull-right">{{ userInfo.phone }}</span>
  30. </li>
  31. </div>
  32. <div class="info-row">
  33. <li class="info-item">
  34. <Icon class="mr-5px" icon="fontisto:email" />
  35. <span class="info-label">邮箱:</span>
  36. <span class="pull-right">{{ userInfo.email }}</span>
  37. </li>
  38. <li class="info-item">
  39. <Icon class="mr-5px" icon="ep:location" />
  40. <span class="info-label">工作间地址:</span>
  41. <span class="pull-right">{{ userInfo.address }}</span>
  42. </li>
  43. </div>
  44. <div class="info-row">
  45. <li class="info-item">
  46. <Icon class="mr-5px" icon="ep:user" />
  47. <span class="info-label">导师人数:</span>
  48. <span class="pull-right">{{ userInfo.supervisorNum }}</span>
  49. </li>
  50. <li class="info-item">
  51. <Icon class="mr-5px" icon="ep:user" />
  52. <span class="info-label">学生人数:</span>
  53. <span class="pull-right">{{ userInfo.studentNum }}</span>
  54. </li>
  55. </div>
  56. <!-- <div>
  57. <li class="info-item">
  58. <Icon class="mr-5px" icon="ep:user" />
  59. <span class="info-label">工作间简介:</span>
  60. <span class="pull-right">{{ userInfo.description }}</span>
  61. </li>
  62. </div> -->
  63. </ul>
  64. <div class="info-description">
  65. <!-- <Icon class="mr-5px" icon="ep:location" /> -->
  66. <div style="display: flex; align-items: center;">
  67. <Icon icon="ep:picture" />
  68. <div class="div-label" style="margin-left: 8px;">简介:</div>
  69. </div>
  70. <div class="description-content">{{ cleanedDescription }}</div>
  71. <div class="image-container">
  72. <div v-for="(url, index) in extractedImageUrls" :key="index" class="image-item">
  73. <img :src="url" />
  74. </div>
  75. </div>
  76. </div>
  77. </el-card>
  78. <DeptForm
  79. ref="formRef"
  80. :visible="dialogVisible"
  81. :form="form"
  82. :rules="rules"
  83. @update:visible="dialogVisible = $event"
  84. @success="handleSuccess"
  85. />
  86. </div>
  87. <div>
  88. <div style="margin-top: 15px;">
  89. <teacher :id="form.id" />
  90. </div>
  91. <div>
  92. <student :id="form.id" />
  93. </div>
  94. </div>
  95. </template>
  96. <script lang="ts">
  97. import { defineComponent, reactive, ref, onMounted } from 'vue';
  98. import type { FormRules } from 'element-plus';
  99. // import type { FormExpose } from '@/components/Form'
  100. import { useI18n } from 'vue-i18n';
  101. import { useMessage } from '@/hooks/web/useMessage';
  102. import { updateDept, DeptVO, getUserDept } from '@/api/system/dept/index';
  103. import * as UserApi from '@/api/system/user'
  104. import DeptForm from './DeptForm.vue';
  105. import student from './student.vue';
  106. import teacher from './teacher.vue';
  107. export default defineComponent({
  108. components: {
  109. DeptForm,
  110. student,
  111. teacher,
  112. },
  113. setup() {
  114. const { t } = useI18n();
  115. const message = useMessage();
  116. const loading = ref(true) // 列表的加载中
  117. const dialogVisible = ref(false);
  118. const formRef = ref();
  119. const form = reactive({
  120. id: '',
  121. supervisor: '',
  122. phone: '',
  123. email: '',
  124. address: '',
  125. name: '',
  126. leaderUserId: [],
  127. nickname: '',
  128. description: '',
  129. });
  130. // 表单校验规则
  131. const rules = reactive<FormRules>({
  132. leaderUserId: [
  133. { required: true, message: '请选择导师名称', trigger: 'blur' }
  134. ],
  135. phone: [
  136. { required: true, message: '请输入负责人电话', trigger: 'blur' },
  137. {
  138. pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
  139. message: '请输入正确的手机号码',
  140. trigger: 'blur'
  141. }
  142. ],
  143. email: [
  144. { required: true, message: '请输入邮箱', trigger: 'blur' },
  145. {
  146. type: 'email',
  147. message: '请输入正确的邮箱格式',
  148. trigger: ['blur', 'change']
  149. }
  150. ],
  151. address: [
  152. { required: true, message: '请输入工作间地址', trigger: 'blur' }
  153. ],
  154. name: [
  155. { required: true, message: '请输入工作间名称', trigger: 'blur' }
  156. ],
  157. description: [
  158. { required: false, message: '请输入工作间简介', trigger: 'blur' }
  159. ],
  160. });
  161. // 将 userInfo 定义放入 setup 中
  162. const userInfo = ref({} as DeptVO);
  163. const fetchUserInfo = async () => {
  164. try{
  165. loading.value = true; // 开始加载状态
  166. const users = await getUserDept();
  167. console.log(users,'userDeptInfo');
  168. userInfo.value = {...users,
  169. // name: users.user[0].nickname // 提取 nickname
  170. };
  171. }finally{
  172. loading.value = false; // 关闭加载状态
  173. }
  174. };
  175. // //获取所有导师
  176. // const users = ref()
  177. // const getSupervisor= async () => {
  178. // try {
  179. // const response = await UserApi.getSupervisor()
  180. // users.value = response
  181. // } catch (error) {
  182. // console.error('Error fetching user data:', error)
  183. // }
  184. // }
  185. // //传supervisorId给form.leaderUserId
  186. // const handleSupervisorChange = (values) => {
  187. // form.leaderUserId = values; // values 是选择的用户ID数组
  188. // }
  189. // const isEditMode = ref(false);
  190. // // 切换编辑模式
  191. // const toggleEditMode = () => {
  192. // if (isEditMode.value) {
  193. // // 在“保存”状态下执行保存操作
  194. // submit();
  195. // }
  196. // isEditMode.value = !isEditMode.value;
  197. // };
  198. const openDialog = () => {
  199. loading.value = true;
  200. dialogVisible.value = true;
  201. formRef.value.open(); // 打开弹窗
  202. };
  203. const extractedImageUrls = ref<string[]>([]);
  204. const handleSuccess = (urls) => {
  205. extractedImageUrls.value = urls;
  206. console.log('提取到的图片URL:', extractedImageUrls);
  207. dialogVisible.value = false;
  208. };
  209. const fetchImageUrls = async () => {
  210. try {
  211. loading.value = true; // 开始加载状态
  212. // 你的获取图片 URL 的 API 调用
  213. const res = await getUserDept();
  214. const urls = res.description.match(/<img.*?src="(.*?)"/g); // 使用更合理的正则表达式
  215. // 如果找到的 URL 数组不为空,则进行处理
  216. if (urls) {
  217. // 从匹配的字符串中提取出 URL
  218. extractedImageUrls.value = urls.map(url => {
  219. // 取出匹配到的 src 属性部分
  220. const match = url.match(/src="(.*?)"/);
  221. return match ? match[1] : '';
  222. });
  223. } else {
  224. extractedImageUrls.value = []; // 没有找到图片则设为空数组
  225. } // 将获取到的 URL 赋值
  226. }finally{
  227. loading.value = false; // 关闭加载状态
  228. }
  229. };
  230. // 创建一个 computed 属性来处理并去掉 <p> 标签
  231. const cleanedDescription = computed(() => {
  232. return userInfo.value.description ? userInfo.value.description.replace(/<\/?[^>]+(>|$)/g, '') : '';
  233. });
  234. // 表单提交
  235. const submit = async () => {
  236. try {
  237. await formRef.value?.validate();
  238. console.log('提交的数据:', form);
  239. await updateDept(form).then((res) => {
  240. console.log('更新成功:', res);
  241. });
  242. message.success('成功');
  243. } catch (error) {
  244. console.error('提交错误:', error);
  245. message.error('错误');
  246. }
  247. };
  248. // 表单重置
  249. const init = async () => {
  250. const res = await getUserDept();
  251. console.log('获取的数据:', res);
  252. form.id = res.id;
  253. form.address = res.address;
  254. form.supervisor = res.user.nickname;
  255. form.phone = res.phone;
  256. form.email = res.email;
  257. form.name = res.name;
  258. form.leaderUserId = res.user.id;
  259. form.description = res.description;
  260. userInfo.value = res.user;
  261. };
  262. onMounted(async () => {
  263. await init();
  264. await fetchUserInfo();
  265. // getSupervisor();
  266. await fetchImageUrls(); // 这里 add 一個方法来加载图片
  267. });
  268. return {
  269. t,
  270. form,
  271. userInfo,
  272. loading,
  273. // isEditMode,
  274. // toggleEditMode,
  275. submit,
  276. init,
  277. rules,
  278. formRef,
  279. // users,
  280. // handleSupervisorChange,
  281. // getSupervisor,
  282. cleanedDescription,
  283. dialogVisible,
  284. openDialog,
  285. handleSuccess,
  286. extractedImageUrls,
  287. };
  288. }
  289. });
  290. </script>
  291. <style scoped>
  292. /* .label-bold {
  293. font-weight: bold;
  294. } */
  295. /* .workspace-name {
  296. height: 20px;
  297. } */
  298. .user-info {
  299. margin-top: 10px;
  300. margin-left: 5%;
  301. margin-right: 5%;
  302. padding-right: 0;
  303. padding-left: 0;
  304. border-right: 0;
  305. border-left: 0;
  306. border-radius: 0;
  307. list-style: none;
  308. }
  309. .info-row {
  310. display: flex;
  311. justify-content: space-between; /* 保持并排显示 */
  312. align-items: center; /* 垂直居中对齐 */
  313. margin-bottom: 20px; /* 增加行之间的间距 */
  314. }
  315. .info-item {
  316. flex: 1; /* 每个信息项占据相同的空间 */
  317. padding: 11px 0; /* 内部上下填充 */
  318. margin-right: 50px; /* 每个信息项之间的右边距 */
  319. }
  320. /* 仅为每个信息项添加底部边框 */
  321. .info-item:first-child {
  322. border-bottom: 1px solid #e7eaec;
  323. }
  324. .info-item:last-child {
  325. border-bottom: 1px solid #e7eaec;
  326. }
  327. .info-description {
  328. margin-top: 30px; /* 与上面的信息分隔 */
  329. margin-left: 5%; /* 左侧与上面列表保持一致 */
  330. margin-right: 5%; /* 右侧与上面列表保持一致 */
  331. /* display: flex; */
  332. align-items: center; /* 确保标题与描述对齐 */
  333. align-items: flex-start;
  334. }
  335. .info-label {
  336. font-weight: bold; /* 加粗标题 */
  337. margin-right: 10px; /* 标题与内容之间的间距 */
  338. }
  339. .div-label {
  340. font-weight: bold; /* 加粗标题 */
  341. display: block;
  342. }
  343. .description-content {
  344. white-space: pre-wrap; /* 保持换行 */
  345. overflow-wrap: break-word; /* 自动断行 */
  346. margin-right: 5%;
  347. font-size: 13px; /* 根据需要设置字体大小 */
  348. margin-top: 20px; /* 内容与标题之间不需要额外间距 */
  349. letter-spacing: 3px;
  350. text-indent: 2em;
  351. line-height: 2;
  352. }
  353. .pull-right {
  354. float: right !important;
  355. }
  356. .info-label {
  357. font-weight: bold;
  358. }
  359. /* .personal-info {
  360. margin-top: 20px;
  361. } */
  362. /* .button-container {
  363. display: flex;
  364. justify-content: center;
  365. margin-top: 30px;
  366. } */
  367. .image-container {
  368. display: flex; /* 使图片横向排列 */
  369. flex-wrap: wrap; /* 如果空间不足则换行 */
  370. gap: 10px; /* 图片之间的间距 */
  371. margin-left: 20px; /* 左边距,根据需要设置 */
  372. }
  373. .image-item img {
  374. width: 150px; /* 设置更大的宽度 */
  375. height: auto; /* 保持高度自动 */
  376. }
  377. </style>