Create.vue 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651
  1. <script setup>
  2. import { ref, reactive, watch, computed, onMounted } from "vue";
  3. import { useMainStore } from "@/stores/store";
  4. import { Loader } from "@googlemaps/js-api-loader";
  5. import VueDatePicker from "@vuepic/vue-datepicker";
  6. import "@vuepic/vue-datepicker/dist/main.css";
  7. import axios from "axios";
  8. import moment from "moment";
  9. import Navbar from "@/components/Navbar.vue";
  10. const store = useMainStore();
  11. const token = store.token;
  12. console.log("token", token);
  13. let step = ref(1);
  14. let stepTitle = ref("");
  15. let stepDescription = ref("");
  16. let loading = ref(false);
  17. const computedTitle = computed(() => {
  18. switch (step.value) {
  19. case 1:
  20. stepTitle.value = "Step1 新增據點";
  21. stepDescription.value = "創建課程之前,請先新增您的據點(上課地址)";
  22. break;
  23. case 2:
  24. stepTitle.value = "Step2 工藝家教學履歷";
  25. stepDescription.value =
  26. "開始打造屬於您的工藝履歷,讓學徒對你印象深刻吧!";
  27. break;
  28. case 3:
  29. stepTitle.value = "Step3 創建課程";
  30. stepDescription.value =
  31. "完整且清楚的課程建立,是連接工藝老師與學徒的重要橋梁!";
  32. break;
  33. case 4:
  34. stepTitle.value = "恭喜您完成創建課程!";
  35. stepDescription.value = "";
  36. break;
  37. }
  38. return { stepTitle: stepTitle.value, stepDescription: stepDescription.value };
  39. });
  40. let date = reactive({
  41. start_date: "", // 起始日期
  42. start_time: "", // 起始時間
  43. end_date: "", // 結束日期
  44. end_time: "", // 結束時間
  45. registration_start_date: "", // 報名起始日期
  46. registration_start_time: "", // 報名起始時間
  47. registration_end_date: "", // 報名截止日期
  48. registration_end_time: "", // 報名截止時間
  49. });
  50. // 處理時間格式(日期+時間)
  51. function mergeAndFormatDateTime(dateString, timeInfo) {
  52. const date = new Date(dateString);
  53. date.setHours(timeInfo.hours);
  54. date.setMinutes(timeInfo.minutes);
  55. date.setSeconds(timeInfo.seconds);
  56. const year = date.getUTCFullYear();
  57. const month = String(date.getUTCMonth() + 1).padStart(2, "0");
  58. const day = String(date.getUTCDate()).padStart(2, "0");
  59. const hours = String(date.getUTCHours()).padStart(2, "0");
  60. const minutes = String(date.getUTCMinutes()).padStart(2, "0");
  61. const seconds = String(date.getUTCSeconds()).padStart(2, "0");
  62. return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}.000Z`;
  63. }
  64. const breadcrumbs = reactive([
  65. {
  66. title: "首頁",
  67. disabled: false,
  68. href: "/",
  69. },
  70. {
  71. title: "我要開課",
  72. disabled: false,
  73. href: "/setup-courses",
  74. },
  75. {
  76. title: "創建課程",
  77. disabled: true,
  78. },
  79. ]);
  80. // Google Map
  81. const states = reactive({
  82. google: null,
  83. map: null,
  84. markers: null,
  85. });
  86. const initMap = async () => {
  87. const loader = new Loader({
  88. apiKey: "AIzaSyAzDeviZ-TpwzT1atlnshNJRjBgndP05Mw",
  89. version: "weekly",
  90. libraries: ["places"],
  91. language: "zh-TW",
  92. });
  93. states.google = await loader.load();
  94. states.map = new states.google.maps.Map(document.getElementById("map"), {
  95. center: { lat: 25.0425, lng: 121.5468 },
  96. zoom: 11,
  97. mapTypeControl: false,
  98. fullscreenControl: false,
  99. });
  100. };
  101. onMounted(async () => {
  102. await initMap();
  103. });
  104. let location = reactive({
  105. location_name: "",
  106. Lng: "",
  107. Lat: "",
  108. address: "",
  109. introduction: "",
  110. email: "",
  111. phone: "",
  112. access_token: token,
  113. });
  114. let locationId = ref("");
  115. async function insertSchool() {
  116. const formData = new FormData();
  117. for (const key in location) {
  118. formData.append(key, location[key]);
  119. }
  120. try {
  121. const response = await axios.post(
  122. "https://cmm.ai:8088/api/insert_school",
  123. formData
  124. );
  125. locationId.value = response.data.location_id;
  126. console.log("新增據點 response", response);
  127. } catch (error) {
  128. console.error(error);
  129. }
  130. }
  131. // 新增履歷
  132. let resume = reactive({
  133. teacher_name: "", // 老師姓名
  134. work_type: "", // 工作性質
  135. experience: "", // 教學經驗
  136. expertise: "", // 專長工藝技能
  137. license: "", // 工藝相關證照
  138. media: "", // 社群媒體
  139. files: [], // 作品集
  140. introduction: "", // 老師介紹
  141. });
  142. async function insertUserResume() {
  143. console.log("insertUserResume", resume);
  144. if (portfolioImg.value.length) {
  145. resume.files = portfolioImg.value;
  146. }
  147. const formData = new FormData();
  148. for (const key in resume) {
  149. if (key === "files") {
  150. resume.files.forEach((file) => {
  151. formData.append("files", file);
  152. });
  153. } else {
  154. formData.append(key, resume[key]);
  155. }
  156. }
  157. let token = store.token;
  158. try {
  159. const response = await axios.post(
  160. `https://cmm.ai:8088/api/input_user_resume?access_token=${token}`,
  161. formData
  162. );
  163. console.log("新增履歷 response", response);
  164. } catch (error) {
  165. console.error(error);
  166. }
  167. }
  168. // 新增課程
  169. let course = reactive({
  170. name: "", // 課程名稱
  171. location_id: "", // 據點編號
  172. category: "", // 工藝類別
  173. introduction: "", // 課程簡介
  174. organizer: "", // 主辦單位
  175. cover_img_file: "", // 課程圖片
  176. group_id: 2, // 學群編號(技藝)
  177. group_sort: "", // 學群細分
  178. special_class_list_name: "",
  179. recommend: 0, // 是否推薦
  180. is_inner: 1, // 內課課程
  181. is_check: 0, // 審核結果
  182. access_token: token,
  183. });
  184. watch(location, (data) => {
  185. course.organizer = data.location_name; // 據點名稱 = 主辦單位
  186. });
  187. let classNameId = ref("");
  188. async function insertClassName() {
  189. console.log("insertClassName", course);
  190. course.location_id = locationId.value;
  191. if (coverImg.value !== "") {
  192. course.cover_img_file = coverImg.value;
  193. }
  194. const formData = new FormData();
  195. for (const key in course) {
  196. formData.append(key, course[key]);
  197. }
  198. try {
  199. const response = await axios.post(
  200. "https://cmm.ai:8088/api/insert_class_name",
  201. formData
  202. );
  203. console.log("新增課程 response", response);
  204. classNameId.value = response.data.new_class_name_id;
  205. } catch (error) {
  206. console.error(error);
  207. }
  208. }
  209. // 新增場次
  210. let event = reactive({
  211. name_id: "", // 課程名稱編號(需先新增課程取得Id)
  212. event: "", // 場次名稱
  213. start_time: "", // 課程起始日
  214. end_time: "", // 課程結束日
  215. contact: "", // 聯絡資訊
  216. lecturer: "", // 課程講師
  217. location: "",
  218. content: "", // 課程內容
  219. URL: "", // 外部連結
  220. people: "不拘", // 對象
  221. fee_method: "", // 課程價格
  222. fee_payment: "", // 收費方式
  223. registration_way: "", // 報名方式
  224. registration_start: "", // 報名起始日
  225. registration_end: "", // 報名截止日
  226. number_limit: "", // 課程名額
  227. remark: "", // 備註
  228. ATM_address: "", // 匯款帳號(銀行代碼+帳號)
  229. access_token: token,
  230. });
  231. let eventType = ref("");
  232. let isOneDay = ref(true);
  233. watch(eventType, (val) => {
  234. if (val === "週期課程(例:2023/10/1~2023/10/30 每週一三上課)") {
  235. isOneDay.value = false;
  236. } else {
  237. isOneDay.value = true;
  238. }
  239. });
  240. let eventData = reactive({
  241. list: [],
  242. });
  243. let isRemit = ref(false); // 是否顯示匯款資訊欄位
  244. let bankCode = ref("");
  245. let bankAccount = ref("");
  246. watch(event, (data) => {
  247. if (data.fee_payment === "匯款") {
  248. isRemit.value = true;
  249. } else {
  250. isRemit.value = false;
  251. }
  252. });
  253. function addEventData() {
  254. // insertSession(); // 測試
  255. // 處理時間格式
  256. event.start_time = mergeAndFormatDateTime(date.start_date, date.start_time);
  257. event.end_time = mergeAndFormatDateTime(date.end_date, date.end_time);
  258. event.registration_start = mergeAndFormatDateTime(
  259. date.registration_start_date,
  260. date.registration_start_time
  261. );
  262. event.registration_end = mergeAndFormatDateTime(
  263. date.registration_end_date,
  264. date.registration_end_time
  265. );
  266. if (isRemit && bankCode.value !== "" && bankAccount.value !== "") {
  267. event.ATM_address = `(${bankCode.value})-${bankAccount.value}`;
  268. }
  269. eventData.list.push(JSON.parse(JSON.stringify(event)));
  270. sessionsDialog.value = false;
  271. }
  272. function convertDateFormat(inputDateStr) {
  273. const inputDate = new Date(inputDateStr);
  274. const formattedDate = inputDate.toISOString();
  275. return formattedDate;
  276. }
  277. let eventId = ref(null);
  278. async function insertEvent() {
  279. console.log("insertEvent", event);
  280. if (classNameId.value !== "") {
  281. event.name_id = classNameId.value;
  282. }
  283. event.start_time = convertDateFormat(event.start_time);
  284. event.end_time = convertDateFormat(event.end_time);
  285. event.registration_start = convertDateFormat(event.registration_start);
  286. event.registration_end = convertDateFormat(event.registration_end);
  287. console.log("檢查日期格式", event);
  288. const formData = new FormData();
  289. for (const key in event) {
  290. formData.append(key, event[key]);
  291. }
  292. try {
  293. const response = await axios.post(
  294. "https://cmm.ai:8088/api/insert_event",
  295. formData
  296. );
  297. eventId.value = response.data.class_id;
  298. console.log("eventId.value", eventId.value);
  299. console.log("新增場次 response", response);
  300. } catch (error) {
  301. console.error(error);
  302. }
  303. }
  304. // 創建課程
  305. async function create() {
  306. loading.value = true;
  307. try {
  308. await insertSchool(); // 新增據點
  309. await insertUserResume(); // 新增履歷
  310. await insertClassName(); // 新增課程
  311. await insertEvent(); // 新增場次
  312. await insertSession(); // 新增課堂
  313. loading.value = false;
  314. step.value++;
  315. } catch (error) {
  316. console.error(error);
  317. loading.value = false;
  318. }
  319. }
  320. const getCoordinates = async () => {
  321. const geocoder = new states.google.maps.Geocoder();
  322. geocoder.geocode({ address: location.address }, (results, status) => {
  323. if (status === states.google.maps.GeocoderStatus.OK) {
  324. location.Lat = results[0].geometry.location.lat();
  325. location.Lng = results[0].geometry.location.lng();
  326. }
  327. // 將地圖中心設為取得的經緯度,並調整縮放等級
  328. states.map.setCenter({ lat: location.Lat, lng: location.Lng });
  329. states.map.setZoom(15);
  330. // 設定地址圖標
  331. const marker = new google.maps.Marker({
  332. position: { lat: location.Lat, lng: location.Lng },
  333. map: states.map,
  334. title: location.address,
  335. icon: store.getImageUrl("map-icon/icon_house05.png"),
  336. });
  337. });
  338. };
  339. // 上傳圖片 Input
  340. const portfolioImgRef = ref(null);
  341. const coverImgRef = ref(null);
  342. const fileInputClick = (ref) => {
  343. if (ref === "portfolio") {
  344. portfolioImgRef.value.click();
  345. } else if (ref === "cover") {
  346. coverImgRef.value.click();
  347. }
  348. };
  349. // 作品集圖片
  350. let portfolioImg = ref([]);
  351. let portfolioImgList = ref([]);
  352. const handlePortfolioImg = (files) => {
  353. console.log("files", files);
  354. // portfolioImgList.value = []; // 清空陣列
  355. for (let index = 0; index < files.length; index++) {
  356. const file = files[index];
  357. console.log("file", file);
  358. let url = URL.createObjectURL(file);
  359. portfolioImgList.value.push(url);
  360. console.log("portfolioImgList", portfolioImgList);
  361. }
  362. };
  363. watch(portfolioImg, (newFiles) => {
  364. if (newFiles.length > 0) {
  365. handlePortfolioImg(newFiles);
  366. }
  367. });
  368. // 封面圖片
  369. let coverImg = ref("");
  370. let coverImgUrl = ref("");
  371. const handleCoverImg = (event) => {
  372. const file = event.target.files[0];
  373. console.log("選擇檔案", file);
  374. if (file) {
  375. coverImg.value = file;
  376. coverImgUrl.value = URL.createObjectURL(file); // 設定圖片預覽 URL
  377. }
  378. };
  379. let sessionsDialog = ref(false);
  380. const requiredRule = (value) => !!value || "此欄位為必填";
  381. const weekList = reactive(["一", "二", "三", "四", "五", "六", "日"]);
  382. const selectedWeek = ref([0, 0, 0, 0, 0, 0, 0]); // 選擇星期
  383. const toggleSelected = (index) => {
  384. if (selectedWeek.value[index]) {
  385. selectedWeek.value[index] = 0;
  386. } else {
  387. selectedWeek.value[index] = 1;
  388. }
  389. };
  390. let session = reactive({
  391. class_event_id: null,
  392. week_day_str: "",
  393. start_week_time: "",
  394. end_week_time: "",
  395. });
  396. let sessionTime = reactive({
  397. start_week_time: [],
  398. end_week_time: [],
  399. });
  400. watch(sessionTime, (val) => {
  401. console.log("sessionTime start_week_time", val.start_week_time);
  402. console.log("sessionTime end_week_time", val.end_week_time);
  403. });
  404. let sessionStartTimeList = ref(["", "", "", "", "", "", ""]);
  405. let sessionEndTimeList = ref(["", "", "", "", "", "", ""]);
  406. // 新增課堂
  407. async function insertSession() {
  408. const weekString = `[${selectedWeek.value.join(",")}]`;
  409. session.week_day_str = weekString;
  410. console.log("weekString", weekString);
  411. selectedWeek.value.map((item, index) => {
  412. if (item) {
  413. console.log("index", index);
  414. // 開始時間
  415. sessionStartTimeList.value[index] = `"${
  416. sessionTime.start_week_time[index].hours < 10 ? "0" : ""
  417. }${sessionTime.start_week_time[index].hours}:${
  418. sessionTime.start_week_time[index].minutes === 0
  419. ? "00"
  420. : sessionTime.start_week_time[index].minutes
  421. }:00"`;
  422. // 結束時間
  423. sessionEndTimeList.value[index] = `"${
  424. sessionTime.end_week_time[index].hours
  425. }:${
  426. sessionTime.end_week_time[index].minutes === 0
  427. ? "00"
  428. : sessionTime.end_week_time[index].minutes
  429. }:00"`;
  430. } else {
  431. sessionStartTimeList.value[index] = '""';
  432. sessionEndTimeList.value[index] = '""';
  433. }
  434. console.log(
  435. "sessionStartTimeList.value[index]",
  436. sessionStartTimeList.value[index]
  437. );
  438. });
  439. session.start_week_time = `[${sessionStartTimeList.value}]`;
  440. session.end_week_time = `[${sessionEndTimeList.value}]`;
  441. session.class_event_id = eventId.value;
  442. console.log("session >>", session);
  443. const formData = new FormData();
  444. for (const key in session) {
  445. formData.append(key, session[key]);
  446. }
  447. try {
  448. const response = await axios.post(
  449. "https://cmm.ai:8088/api/auto_create_session",
  450. formData
  451. );
  452. console.log("新增課堂 response", response);
  453. } catch (error) {
  454. console.error(error);
  455. }
  456. }
  457. </script>
  458. <template>
  459. <Navbar />
  460. <v-container class="mb-16 pb-16">
  461. <v-breadcrumbs
  462. :items="breadcrumbs"
  463. divider="/"
  464. class="py-10"
  465. ></v-breadcrumbs>
  466. <v-card class="mx-auto pa-10">
  467. <v-card-title class="step-title">
  468. <h5>{{ computedTitle.stepTitle }}</h5>
  469. <p class="mt-5">{{ computedTitle.stepDescription }}</p>
  470. </v-card-title>
  471. <v-window v-model="step">
  472. <v-window-item :value="1">
  473. <v-card-text>
  474. <v-label class="d-flex align-center pb-3">
  475. <p class="pb-5 pe-3">據點名稱<span class="mark">*</span></p>
  476. <v-text-field
  477. v-model="location.location_name"
  478. :rules="[requiredRule]"
  479. placeholder="可以是您的工作室或品牌名稱/教學單位/您的姓名"
  480. density="compact"
  481. variant="outlined"
  482. counter
  483. maxlength="60"
  484. ></v-text-field>
  485. </v-label>
  486. <v-label class="d-flex align-center pb-3 w-100">
  487. <p class="pb-5 pe-3">據點地址<span class="mark">*</span></p>
  488. <v-text-field
  489. v-model="location.address"
  490. :rules="[requiredRule]"
  491. density="compact"
  492. variant="outlined"
  493. placeholder="需在安全且便於學徒到達之地點開課"
  494. ></v-text-field>
  495. <v-btn
  496. @click="getCoordinates"
  497. color="purple"
  498. variant="flat"
  499. class="ms-3 mb-6 px-8"
  500. >
  501. 查詢
  502. </v-btn>
  503. </v-label>
  504. <div class="d-flex flex-column justify-end ms-16 ps-5">
  505. <div
  506. class="map"
  507. id="map"
  508. style="width: 100%; height: 500px"
  509. ></div>
  510. <v-row class="mt-3">
  511. <v-col cols="12" md="6">
  512. <v-label class="d-flex align-center">
  513. <p class="pb-5 pe-3">經度</p>
  514. <v-text-field
  515. v-model="location.Lng"
  516. density="compact"
  517. variant="outlined"
  518. disabled
  519. ></v-text-field>
  520. </v-label>
  521. </v-col>
  522. <v-col cols="12" md="6">
  523. <v-label class="d-flex align-center">
  524. <p class="pb-5 pe-3">緯度</p>
  525. <v-text-field
  526. v-model="location.Lat"
  527. density="compact"
  528. variant="outlined"
  529. disabled
  530. ></v-text-field>
  531. </v-label>
  532. </v-col>
  533. </v-row>
  534. </div>
  535. <v-label class="d-block">
  536. <p class="d-flex mb-5">據點 Email<span class="mark">*</span></p>
  537. <v-text-field
  538. v-model="location.email"
  539. :rules="[requiredRule]"
  540. density="compact"
  541. variant="outlined"
  542. placeholder="請填寫 Email"
  543. ></v-text-field>
  544. </v-label>
  545. <v-row class="mt-3">
  546. <v-col cols="12" md="12">
  547. <v-label class="d-block">
  548. <p class="d-flex">公開電話<span class="mark">*</span></p>
  549. <span class="d-block py-3 hint"
  550. >會顯示於課程介紹中,想了解課程資訊者聯繫用途</span
  551. >
  552. <v-text-field
  553. v-model="location.phone"
  554. :rules="[requiredRule]"
  555. density="compact"
  556. variant="outlined"
  557. ></v-text-field>
  558. </v-label>
  559. </v-col>
  560. <!-- <v-col cols="12" md="6">
  561. <v-label class="d-block">
  562. <p class="d-flex">聯繫電話<span class="mark">*</span></p>
  563. <span class="d-block py-3 hint">平台專員連繫重要事項用</span>
  564. <v-text-field
  565. :rules="[(v) => !!v || '請輸入電話']"
  566. density="compact"
  567. variant="outlined"
  568. ></v-text-field>
  569. </v-label>
  570. </v-col> -->
  571. <!-- <v-col cols="12" md="6">
  572. <v-label class="d-block">
  573. <p class="d-flex">上傳據點照片</p>
  574. <v-file-input
  575. ref="fileInputRef"
  576. label="File input"
  577. variant="outlined"
  578. placeholder="選擇相片上傳"
  579. @change="handlePortfolioImg"
  580. style="display: none"
  581. ></v-file-input>
  582. </v-label>
  583. <v-btn @click="openFileInput" color="purple" class="my-5"
  584. >選擇相片上傳</v-btn
  585. >
  586. <div class="step-01 image-preview">
  587. <img
  588. v-if="selectedFile"
  589. :src="selectedFileUrl"
  590. alt="上傳圖片預覽"
  591. />
  592. </div>
  593. </v-col> -->
  594. <v-col cols="12" md="12">
  595. <v-label class="d-block">
  596. <p class="d-flex mb-5">據點簡介<span class="mark">*</span></p>
  597. <v-textarea
  598. v-model="location.introduction"
  599. rows="5"
  600. variant="outlined"
  601. ></v-textarea>
  602. </v-label>
  603. </v-col>
  604. </v-row>
  605. </v-card-text>
  606. </v-window-item>
  607. <v-window-item :value="2">
  608. <v-card-text>
  609. <v-row>
  610. <v-col cols="6">
  611. <v-label class="d-flex align-center pb-3">
  612. <p class="pb-5 pe-3">老師姓名<span class="mark">*</span></p>
  613. <v-text-field
  614. v-model="resume.teacher_name"
  615. :rules="[requiredRule]"
  616. density="compact"
  617. variant="outlined"
  618. ></v-text-field>
  619. </v-label>
  620. </v-col>
  621. <v-col cols="6"></v-col>
  622. <v-col cols="3">
  623. <v-label class="d-block">
  624. <p class="pb-5 pe-3">工作性質<span class="mark">*</span></p>
  625. <v-radio-group v-model="resume.work_type" inline>
  626. <v-radio label="全職" value="全職"></v-radio>
  627. <v-radio label="兼職" value="兼職" class="ps-3"></v-radio>
  628. </v-radio-group>
  629. </v-label>
  630. </v-col>
  631. <v-col cols="9">
  632. <v-label class="d-block">
  633. <p class="pb-5 pe-3">教學經驗</p>
  634. <v-radio-group v-model="resume.experience" inline>
  635. <v-radio label="0-5 年" value="0-5 年"></v-radio>
  636. <v-radio
  637. label="5-10 年"
  638. value="5-10 年"
  639. class="ps-3"
  640. ></v-radio>
  641. <v-radio
  642. label="10-20 年"
  643. value="10-20 年"
  644. class="ps-3"
  645. ></v-radio>
  646. <v-radio
  647. label="20 年以上"
  648. value="20 年以上"
  649. class="ps-3"
  650. ></v-radio>
  651. </v-radio-group>
  652. </v-label>
  653. </v-col>
  654. <v-col cols="6">
  655. <v-label class="d-block pb-3">
  656. <p class="pb-5 pe-3">
  657. 專長工藝技能<span class="mark">*</span>
  658. </p>
  659. <v-text-field
  660. v-model="resume.expertise"
  661. :rules="[requiredRule]"
  662. density="compact"
  663. variant="outlined"
  664. ></v-text-field>
  665. </v-label>
  666. <v-label class="d-block pb-3">
  667. <p class="pb-5 pe-3">工藝相關證照</p>
  668. <v-text-field
  669. v-model="resume.license"
  670. density="compact"
  671. variant="outlined"
  672. ></v-text-field>
  673. </v-label>
  674. <v-label class="d-block">
  675. <p class="d-flex">社群媒體</p>
  676. <span class="d-block py-3 hint"
  677. >工藝老師經營之網站或社群媒體,可貼網址</span
  678. >
  679. <v-text-field
  680. v-model="resume.media"
  681. density="compact"
  682. variant="outlined"
  683. ></v-text-field>
  684. </v-label>
  685. </v-col>
  686. <v-col cols="6">
  687. <v-label class="d-block">
  688. <p class="d-flex">講師作品集</p>
  689. <v-file-input
  690. multiple
  691. v-model="portfolioImg"
  692. ref="portfolioImgRef"
  693. label="File input"
  694. variant="outlined"
  695. placeholder="選擇相片上傳"
  696. @change="handlePortfolioImg"
  697. style="display: none"
  698. ></v-file-input>
  699. </v-label>
  700. <v-btn
  701. @click="fileInputClick('portfolio')"
  702. color="purple"
  703. class="my-5"
  704. >選擇相片上傳</v-btn
  705. >
  706. <v-row class="img-list">
  707. <v-col cols="4" v-for="(item, index) in 6" :key="index">
  708. <div v-if="!portfolioImgList.length" class="item"></div>
  709. <div
  710. v-else
  711. class="item"
  712. :style="{
  713. backgroundImage: `url('${portfolioImgList[index]}')`,
  714. }"
  715. ></div>
  716. </v-col>
  717. </v-row>
  718. <!-- <div class="step-02 image-preview">
  719. <img
  720. v-if="selectedFile"
  721. :src="selectedFileUrl"
  722. alt="上傳圖片預覽"
  723. />
  724. </div> -->
  725. </v-col>
  726. <v-col cols="12">
  727. <v-label class="d-block">
  728. <p class="d-flex mb-5">老師自我介紹</p>
  729. <v-textarea
  730. v-model="resume.introduction"
  731. rows="5"
  732. variant="outlined"
  733. ></v-textarea>
  734. </v-label>
  735. </v-col>
  736. </v-row>
  737. </v-card-text>
  738. </v-window-item>
  739. <v-window-item :value="3">
  740. <v-card-text class="mb-7">
  741. <v-row class="justify-space-evenly">
  742. <v-col cols="12" md="5">
  743. <v-label class="d-block pb-3">
  744. <p class="pb-5 pe-3">課程名稱<span class="mark">*</span></p>
  745. <v-text-field
  746. v-model="course.name"
  747. :rules="[requiredRule]"
  748. density="compact"
  749. variant="outlined"
  750. ></v-text-field>
  751. </v-label>
  752. </v-col>
  753. <!-- <v-col cols="12" md="5">
  754. <v-label class="d-block pb-3">
  755. <p class="pb-5 pe-3">課程價格<span class="mark">*</span></p>
  756. <v-text-field
  757. :rules="[requiredRule]"
  758. density="compact"
  759. variant="outlined"
  760. ></v-text-field>
  761. </v-label>
  762. </v-col> -->
  763. <v-col cols="12" md="5">
  764. <v-label class="d-block pb-3">
  765. <p class="pb-5 pe-3">工藝類別<span class="mark">*</span></p>
  766. <v-select
  767. v-model="course.category"
  768. placeholder="請選擇類別"
  769. :items="[
  770. '樹藝',
  771. '漆藝',
  772. '藍染',
  773. '蠟雕',
  774. '竹工藝籃',
  775. '金工/飾品',
  776. '蠟燭/香氛/調香',
  777. '植栽/花藝',
  778. '插畫/繪畫/寫字',
  779. '皮件/皮革',
  780. '木工/竹藝',
  781. '陶藝/玻璃',
  782. '編織/羊毛氈/縫紉',
  783. '其他',
  784. ]"
  785. :rules="[requiredRule]"
  786. hide-details
  787. density="compact"
  788. variant="outlined"
  789. ></v-select>
  790. </v-label>
  791. </v-col>
  792. <!-- <v-col cols="12" md="5">
  793. <v-label class="d-block pb-3">
  794. <p class="pb-5 pe-3">
  795. 適合報名對象(年紀)<span class="mark">*</span>
  796. </p>
  797. <v-select
  798. v-model="age"
  799. :items="[
  800. '不拘',
  801. '7 歲以下',
  802. '7-18 歲',
  803. '18-65 歲',
  804. '65 歲以上',
  805. ]"
  806. :rules="[requiredRule]"
  807. density="compact"
  808. variant="outlined"
  809. outlined
  810. ></v-select>
  811. </v-label>
  812. </v-col> -->
  813. <v-col cols="12" md="5">
  814. <v-label class="d-block pb-3">
  815. <p class="pb-5 pe-3">上課地點</p>
  816. <v-text-field
  817. v-model="location.address"
  818. label="自動帶入據點地址"
  819. density="compact"
  820. variant="outlined"
  821. ></v-text-field>
  822. </v-label>
  823. </v-col>
  824. <v-col cols="12" md="5">
  825. <v-label class="d-block pb-3">
  826. <p class="pb-5 pe-3">主辦單位</p>
  827. <v-text-field
  828. v-model="location.location_name"
  829. label="自動帶入據點名稱"
  830. density="compact"
  831. variant="outlined"
  832. ></v-text-field>
  833. </v-label>
  834. </v-col>
  835. <v-col cols="12" md="11" class="px-7">
  836. <v-label class="d-block">
  837. <p class="d-flex">課程時間<span class="mark">*</span></p>
  838. <!-- <v-btn color="purple" class="my-5"
  839. >
  840. <v-icon icon="mdi-plus" class="me-1"></v-icon>
  841. 建立新場次</v-btn
  842. > -->
  843. <v-dialog v-model="sessionsDialog" persistent width="800">
  844. <template v-slot:activator="{ props }">
  845. <v-btn class="my-5" color="purple" v-bind="props">
  846. <v-icon icon="mdi-plus" class="me-1"></v-icon>
  847. 建立新場次
  848. </v-btn>
  849. </template>
  850. <v-card class="sessions-card pb-3">
  851. <v-card-title>
  852. <span class="d-block ps-10 py-5">建立新場次</span>
  853. </v-card-title>
  854. <v-card-text class="pt-0 px-8">
  855. <v-container class="py-0">
  856. <v-row>
  857. <v-col cols="12" sm="6" class="date-item">
  858. <p class="mb-0 pe-3">
  859. 起始日期<span class="mark">*</span>
  860. </p>
  861. <VueDatePicker
  862. v-model="date.start_date"
  863. :min-date="new Date()"
  864. :enable-time-picker="false"
  865. :format="store.datePickerFormat"
  866. locale="cn"
  867. ></VueDatePicker>
  868. </v-col>
  869. <v-col cols="12" sm="6" class="date-item">
  870. <p class="mb-0 pe-3">
  871. 起始時間<span class="mark">*</span>
  872. </p>
  873. <VueDatePicker
  874. v-model="date.start_time"
  875. time-picker
  876. />
  877. </v-col>
  878. <v-col cols="12" sm="6" class="date-item">
  879. <p class="mb-0 pe-3">
  880. 結束日期<span class="mark">*</span>
  881. </p>
  882. <VueDatePicker
  883. v-model="date.end_date"
  884. :min-date="new Date()"
  885. :enable-time-picker="false"
  886. :format="store.datePickerFormat"
  887. locale="cn"
  888. ></VueDatePicker>
  889. </v-col>
  890. <v-col cols="12" sm="6" class="date-item">
  891. <p class="mb-0 pe-3">
  892. 結束時間<span class="mark">*</span>
  893. </p>
  894. <VueDatePicker
  895. v-model="date.end_time"
  896. time-picker
  897. />
  898. </v-col>
  899. <v-divider class="mt-5 mb-8"></v-divider>
  900. <v-col cols="12" sm="6" class="py-0">
  901. <v-label class="d-flex align-center py-2">
  902. <p class="pb-5 pe-3">
  903. 場次名稱<span class="mark">*</span>
  904. </p>
  905. <v-text-field
  906. v-model="event.event"
  907. :rules="[requiredRule]"
  908. density="compact"
  909. variant="outlined"
  910. ></v-text-field>
  911. </v-label>
  912. </v-col>
  913. <v-col cols="12" sm="6" class="py-0">
  914. <v-label class="d-flex align-center py-2">
  915. <p class="pb-5 pe-3">
  916. 課程講師<span class="mark">*</span>
  917. </p>
  918. <v-text-field
  919. v-model="event.lecturer"
  920. :rules="[requiredRule]"
  921. density="compact"
  922. variant="outlined"
  923. ></v-text-field>
  924. </v-label>
  925. </v-col>
  926. <v-col cols="12" sm="6" class="py-0">
  927. <v-label class="d-flex align-center py-2">
  928. <p class="pb-5 pe-3">
  929. 聯絡資訊<span class="mark">*</span>
  930. </p>
  931. <v-text-field
  932. v-model="event.contact"
  933. :rules="[requiredRule]"
  934. density="compact"
  935. variant="outlined"
  936. ></v-text-field>
  937. </v-label>
  938. </v-col>
  939. <v-col cols="12" sm="6" class="py-0">
  940. <v-label class="d-flex align-center py-2">
  941. <p class="pb-5 pe-3">
  942. 課程名額<span class="mark">*</span>
  943. </p>
  944. <v-text-field
  945. v-model="event.number_limit"
  946. :rules="[requiredRule]"
  947. density="compact"
  948. variant="outlined"
  949. type="number"
  950. hint="請設定報名人數上限"
  951. ></v-text-field>
  952. </v-label>
  953. </v-col>
  954. <v-col cols="12" class="py-0">
  955. <v-label class="d-flex align-center py-2">
  956. <p class="pb-5 pe-3">
  957. 收費方式<span class="mark">*</span>
  958. </p>
  959. <v-select
  960. v-model="event.fee_payment"
  961. :items="['現場收費', '匯款']"
  962. :rules="[requiredRule]"
  963. density="compact"
  964. variant="outlined"
  965. outlined
  966. ></v-select>
  967. </v-label>
  968. </v-col>
  969. <v-col cols="12" class="py-0">
  970. <v-label
  971. v-if="isRemit"
  972. class="d-flex align-center py-2"
  973. >
  974. <p class="pb-5 pe-3">
  975. 匯款資訊<span class="mark">*</span>
  976. </p>
  977. <div class="d-flex w-100">
  978. <v-text-field
  979. v-model="bankCode"
  980. label="銀行代碼"
  981. :rules="[requiredRule]"
  982. density="compact"
  983. variant="outlined"
  984. style="width: 30%"
  985. class="me-3"
  986. ></v-text-field>
  987. <v-text-field
  988. v-model="bankAccount"
  989. label="匯款帳號 (10-16 碼)"
  990. :rules="[requiredRule]"
  991. density="compact"
  992. variant="outlined"
  993. style="width: 70%"
  994. ></v-text-field>
  995. </div>
  996. </v-label>
  997. </v-col>
  998. <v-col cols="12" sm="6" class="py-0">
  999. <v-label class="d-flex align-center py-2">
  1000. <p class="pb-5 pe-3">
  1001. 課程價格<span class="mark">*</span>
  1002. </p>
  1003. <v-text-field
  1004. v-model="event.fee_method"
  1005. :rules="[requiredRule]"
  1006. density="compact"
  1007. variant="outlined"
  1008. ></v-text-field>
  1009. </v-label>
  1010. </v-col>
  1011. <v-col cols="12" sm="6" class="py-0">
  1012. <v-label class="d-flex align-center">
  1013. <p class="pb-3 pe-5">
  1014. 適合報名<br />對象<span class="mark pb-4"
  1015. >*</span
  1016. >
  1017. </p>
  1018. <v-select
  1019. v-model="event.people"
  1020. :items="[
  1021. '不拘',
  1022. '7 歲以下',
  1023. '7-18 歲',
  1024. '18-65 歲',
  1025. '65 歲以上',
  1026. ]"
  1027. :rules="[requiredRule]"
  1028. density="compact"
  1029. variant="outlined"
  1030. outlined
  1031. ></v-select>
  1032. <!-- <v-text-field
  1033. :rules="[requiredRule]"
  1034. density="compact"
  1035. variant="outlined"
  1036. ></v-text-field> -->
  1037. </v-label>
  1038. </v-col>
  1039. <v-col cols="12" class="py-0 position-relative">
  1040. <v-label class="d-flex align-center py-2">
  1041. <p class="pb-3 pe-3">
  1042. 課程類型<span class="mark pb-4">*</span>
  1043. </p>
  1044. <v-select
  1045. v-model="eventType"
  1046. :items="[
  1047. '一日課程(例:2023/10/2 週一上課)',
  1048. '週期課程(例:2023/10/1~2023/10/30 每週一三上課)',
  1049. ]"
  1050. :rules="[requiredRule]"
  1051. density="compact"
  1052. variant="outlined"
  1053. outlined
  1054. ></v-select>
  1055. </v-label>
  1056. <!-- <small
  1057. v-show="eventType !== ''"
  1058. class="type-hint"
  1059. >{{
  1060. isOneDay
  1061. ? "例:2023/10/2 週一上課"
  1062. : "例:2023/10/1~2023/10/30 每週一三上課"
  1063. }}</small
  1064. > -->
  1065. </v-col>
  1066. <v-col
  1067. v-if="!isOneDay"
  1068. cols="12"
  1069. class="d-flex py-0"
  1070. >
  1071. <p class="pt-1 pe-3">
  1072. 重複週期<span class="mark pb-4">*</span>
  1073. </p>
  1074. <ul class="week-list">
  1075. <li
  1076. v-for="(item, index) in weekList"
  1077. :key="index"
  1078. @click="toggleSelected(index)"
  1079. :class="{ active: selectedWeek[index] }"
  1080. class="d-flex"
  1081. >
  1082. <button>
  1083. {{ item }}
  1084. </button>
  1085. <div
  1086. v-if="selectedWeek[index]"
  1087. class="d-flex w-100 ms-5"
  1088. >
  1089. <VueDatePicker
  1090. v-model="
  1091. sessionTime.start_week_time[index]
  1092. "
  1093. time-picker
  1094. />
  1095. <span class="d-flex align-center mx-2"
  1096. >~</span
  1097. >
  1098. <VueDatePicker
  1099. v-model="sessionTime.end_week_time[index]"
  1100. time-picker
  1101. />
  1102. </div>
  1103. </li>
  1104. </ul>
  1105. </v-col>
  1106. <!-- <v-col
  1107. v-if="!isOneDay"
  1108. cols="12"
  1109. class="time-item pt-5 pb-7"
  1110. >
  1111. <p class="mb-0">
  1112. 課程時間<span class="mark">*</span>
  1113. </p>
  1114. <div class="d-flex w-100">
  1115. <VueDatePicker
  1116. v-model="sessionTime.start_week_time"
  1117. time-picker
  1118. />
  1119. <span class="d-flex align-center mx-2">~</span>
  1120. <VueDatePicker
  1121. v-model="sessionTime.end_week_time"
  1122. time-picker
  1123. />
  1124. </div>
  1125. </v-col> -->
  1126. <v-col cols="12" class="py-0">
  1127. <v-label class="d-flex align-center py-2">
  1128. <p class="pe-3">備註</p>
  1129. <v-text-field
  1130. v-model="event.remark"
  1131. density="compact"
  1132. variant="outlined"
  1133. hide-details
  1134. ></v-text-field>
  1135. </v-label>
  1136. </v-col>
  1137. <v-divider class="my-8"></v-divider>
  1138. <v-col cols="12" sm="6" class="date-item">
  1139. <p class="mb-0 pe-3">
  1140. 報名日期<span class="mark pb-4">*</span>
  1141. </p>
  1142. <VueDatePicker
  1143. v-model="date.registration_start_date"
  1144. :min-date="new Date()"
  1145. :enable-time-picker="false"
  1146. :format="store.datePickerFormat"
  1147. locale="cn"
  1148. ></VueDatePicker>
  1149. </v-col>
  1150. <v-col cols="12" sm="6" class="date-item">
  1151. <p class="mb-0 pe-3">
  1152. 報名時間<span class="mark pb-4">*</span>
  1153. </p>
  1154. <VueDatePicker
  1155. v-model="date.registration_start_time"
  1156. time-picker
  1157. />
  1158. </v-col>
  1159. <v-col cols="12" sm="6" class="date-item">
  1160. <p class="mb-0 pe-3">
  1161. 報名截止<span class="mark pb-4">*</span>
  1162. </p>
  1163. <VueDatePicker
  1164. v-model="date.registration_end_date"
  1165. :min-date="new Date()"
  1166. :enable-time-picker="false"
  1167. :format="store.datePickerFormat"
  1168. locale="cn"
  1169. ></VueDatePicker>
  1170. </v-col>
  1171. <v-col cols="12" sm="6" class="date-item">
  1172. <p class="mb-0 pe-3">
  1173. 截止時間<span class="mark pb-4">*</span>
  1174. </p>
  1175. <VueDatePicker
  1176. v-model="date.registration_end_time"
  1177. time-picker
  1178. />
  1179. </v-col>
  1180. </v-row>
  1181. </v-container>
  1182. </v-card-text>
  1183. <v-card-actions class="justify-center pt-10 pb-5">
  1184. <v-btn
  1185. color="gray"
  1186. variant="tonal"
  1187. class="me-3 px-10"
  1188. @click="sessionsDialog = false"
  1189. >
  1190. 取消
  1191. </v-btn>
  1192. <v-btn
  1193. color="purple"
  1194. variant="flat"
  1195. @click="addEventData()"
  1196. class="px-10"
  1197. >
  1198. 新增
  1199. </v-btn>
  1200. </v-card-actions>
  1201. </v-card>
  1202. </v-dialog>
  1203. <div v-if="eventData.list.length" class="main-table">
  1204. <h6 class="table-title">場次資訊</h6>
  1205. <table>
  1206. <thead>
  1207. <tr>
  1208. <th>名稱</th>
  1209. <th>日期</th>
  1210. <th width="20%">課程講師</th>
  1211. <th width="20%">收費方式</th>
  1212. </tr>
  1213. </thead>
  1214. <tbody>
  1215. <tr
  1216. v-for="(item, index) in eventData.list"
  1217. :key="index"
  1218. >
  1219. <td>{{ item.event }}</td>
  1220. <td>
  1221. {{
  1222. moment(`${item.start_time}`).format("YYYY/MM/DD")
  1223. }}
  1224. <br />
  1225. <br />
  1226. {{
  1227. moment(`${item.end_time}`).format("YYYY/MM/DD")
  1228. }}
  1229. </td>
  1230. <td>{{ item.lecturer }}</td>
  1231. <td>{{ item.fee_method }}</td>
  1232. </tr>
  1233. </tbody>
  1234. </table>
  1235. </div>
  1236. </v-label>
  1237. </v-col>
  1238. <v-col cols="12" md="11" class="px-7">
  1239. <v-label class="d-block">
  1240. <p class="d-flex">課程簡介<span class="mark">*</span></p>
  1241. <small class="d-block text-gray my-2"
  1242. >內容不得少於 100 字元,且不得含有工藝無關之資訊</small
  1243. >
  1244. <v-textarea
  1245. v-model="course.introduction"
  1246. rows="5"
  1247. variant="outlined"
  1248. ></v-textarea>
  1249. </v-label>
  1250. </v-col>
  1251. <v-col cols="12" md="6" class="me-auto ms-3 ps-16">
  1252. <v-label class="d-block">
  1253. <p class="d-flex">上傳課程封面<span class="mark">*</span></p>
  1254. <v-file-input
  1255. multiple
  1256. v-model="coverImg"
  1257. ref="coverImgRef"
  1258. label="File input"
  1259. variant="outlined"
  1260. placeholder="選擇相片上傳"
  1261. @change="handleCoverImg"
  1262. style="display: none"
  1263. ></v-file-input>
  1264. </v-label>
  1265. <v-btn
  1266. @click="fileInputClick('cover')"
  1267. color="purple"
  1268. class="my-5"
  1269. >選擇相片上傳</v-btn
  1270. >
  1271. <div class="step-01 image-preview">
  1272. <img v-if="coverImg" :src="coverImgUrl" alt="上傳圖片預覽" />
  1273. </div>
  1274. <!-- <v-row class="img-list">
  1275. <v-col cols="4" v-for="(item, index) in 6" :key="index">
  1276. <div v-if="!portfolioImgList.length" class="item"></div>
  1277. <div
  1278. v-else
  1279. class="item"
  1280. :style="{
  1281. backgroundImage: `url('${portfolioImgList[index]}')`,
  1282. }"
  1283. ></div>
  1284. </v-col>
  1285. </v-row> -->
  1286. </v-col>
  1287. </v-row>
  1288. </v-card-text>
  1289. </v-window-item>
  1290. <v-window-item :value="4">
  1291. <v-card-text class="mb-7 finish-step">
  1292. <p>
  1293. 請等待後台人員確認您的課程資訊 <br />
  1294. 待您收到開課完成的 Email <br />
  1295. 就可以前往
  1296. <router-link to="/user/courses">【我的開課】</router-link>
  1297. 觀看及修改您的
  1298. </p>
  1299. <ul>
  1300. <li>(1) 據點資訊</li>
  1301. <li>(2) 工藝家履歷</li>
  1302. <li>(3) 課程清單</li>
  1303. </ul>
  1304. </v-card-text>
  1305. </v-window-item>
  1306. </v-window>
  1307. <v-divider></v-divider>
  1308. <v-card-actions class="justify-center mt-7">
  1309. <v-btn
  1310. v-if="step > 1 && step !== 4"
  1311. color="gray"
  1312. variant="outlined"
  1313. @click="step--"
  1314. class="px-7 me-2"
  1315. >
  1316. 上一步
  1317. </v-btn>
  1318. <v-spacer></v-spacer>
  1319. <v-btn
  1320. v-if="step < 3"
  1321. color="purple"
  1322. variant="flat"
  1323. @click="step++"
  1324. class="px-7"
  1325. >
  1326. 下一步
  1327. </v-btn>
  1328. <v-btn
  1329. v-if="step === 3"
  1330. color="purple"
  1331. variant="flat"
  1332. @click="create()"
  1333. :loading="loading"
  1334. class="px-7"
  1335. >
  1336. 創建
  1337. </v-btn>
  1338. <v-btn v-if="step === 4" color="purple" variant="outlined" class="me-3">
  1339. <router-link to="/" class="px-7">回到首頁</router-link>
  1340. </v-btn>
  1341. <v-btn v-if="step === 4" color="purple" variant="flat">
  1342. <router-link to="/user/courses" class="px-7"
  1343. >前往開課專區</router-link
  1344. >
  1345. </v-btn>
  1346. </v-card-actions>
  1347. </v-card>
  1348. </v-container>
  1349. </template>
  1350. <style lang="scss" scoped>
  1351. .step-title {
  1352. text-align: center;
  1353. h5 {
  1354. font-size: 28px;
  1355. font-weight: 500;
  1356. letter-spacing: 2px;
  1357. }
  1358. p {
  1359. font-size: 16px;
  1360. font-weight: 400;
  1361. letter-spacing: 1px;
  1362. color: #919191;
  1363. }
  1364. }
  1365. .step-01 {
  1366. &.image-preview {
  1367. height: 285px;
  1368. }
  1369. }
  1370. .step-02 {
  1371. &.image-preview {
  1372. height: 235px;
  1373. }
  1374. }
  1375. .image-preview {
  1376. img {
  1377. height: 100%;
  1378. object-fit: contain;
  1379. }
  1380. }
  1381. .flex-grow-1 {
  1382. display: none !important;
  1383. }
  1384. .img-list {
  1385. .item {
  1386. height: 105px;
  1387. border-radius: 5px;
  1388. background-color: #ccc; // 預設灰底
  1389. background-repeat: no-repeat;
  1390. background-position: center;
  1391. background-size: cover;
  1392. }
  1393. }
  1394. .sessions-card {
  1395. border-radius: 30px 5px 5px 30px !important;
  1396. .v-label {
  1397. p {
  1398. width: 95px;
  1399. text-align: end;
  1400. line-height: 22px;
  1401. @media (max-width: 600px) {
  1402. width: 123px;
  1403. }
  1404. }
  1405. }
  1406. }
  1407. .date-item {
  1408. display: flex;
  1409. margin-bottom: 10px;
  1410. p {
  1411. width: 114px;
  1412. display: flex;
  1413. align-items: center;
  1414. justify-content: end;
  1415. white-space: nowrap;
  1416. line-height: 22px;
  1417. @media (max-width: 600px) {
  1418. width: 125px;
  1419. }
  1420. }
  1421. }
  1422. .main-table {
  1423. margin: 50px 0;
  1424. .table-title {
  1425. background-color: var(--purple);
  1426. }
  1427. table {
  1428. thead {
  1429. border-bottom: 2px solid var(--purple);
  1430. }
  1431. tbody {
  1432. td {
  1433. border-bottom: 1px solid var(--purple);
  1434. }
  1435. }
  1436. }
  1437. }
  1438. .finish-step {
  1439. line-height: 50px;
  1440. font-size: 22px;
  1441. text-align: center;
  1442. letter-spacing: 1px;
  1443. }
  1444. .type-hint {
  1445. width: 100%;
  1446. display: block;
  1447. position: absolute;
  1448. bottom: 1px;
  1449. left: 105px;
  1450. color: var(--gray);
  1451. }
  1452. .week-list {
  1453. height: 70%;
  1454. align-items: center;
  1455. li {
  1456. margin: 15px 0;
  1457. button {
  1458. color: var(--purple);
  1459. padding: 10px;
  1460. border-radius: 100px;
  1461. border: 1px solid var(--purple);
  1462. transition: all 0.3s;
  1463. &:hover {
  1464. color: #fff;
  1465. background-color: var(--purple);
  1466. }
  1467. }
  1468. &.active {
  1469. button {
  1470. color: #fff;
  1471. background-color: var(--purple);
  1472. }
  1473. }
  1474. }
  1475. }
  1476. .time-item {
  1477. display: flex;
  1478. align-items: center;
  1479. p {
  1480. width: 97px;
  1481. flex-wrap: nowrap;
  1482. display: flex;
  1483. white-space: nowrap;
  1484. }
  1485. }
  1486. </style>