index.vue 12 KB

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