diff --git a/src/api/certification.ts b/src/api/certification.ts index 37fe370..13b37e2 100644 --- a/src/api/certification.ts +++ b/src/api/certification.ts @@ -31,4 +31,4 @@ export const certificationTypeListApi = () => { url: '/v1/mall/enum/companyAuthenticationType', method: 'get', }) -} +} diff --git a/src/api/codeManage.ts b/src/api/codeManage.ts new file mode 100644 index 0000000..5726cb9 --- /dev/null +++ b/src/api/codeManage.ts @@ -0,0 +1,67 @@ +import { useRequest } from '@/use/useHttp' + +/** + * 获取自定义码单详情 + * @returns + */ +export const GetCustomCodeDetailApi = () => { + return useRequest({ + url: '/v1/mall/customPrint', + method: 'get', + }) +} + +/** + * 获取自定义码单列表 + * @returns + */ +export const GetCustomCodeLApi = () => { + return useRequest({ + url: '/v1/mall/customPrint/list', + method: 'get', + }) +} + +/** + * 获取初始化自定义码单 + * @returns + */ +export const GetCustomCodeInitApi = () => { + return useRequest({ + url: '/v1/mall/customPrint/init', + method: 'get', + }) +} + +/** + * 更新自定义码单 + * @returns + */ +export const UpdateCustomCodeApi = () => { + return useRequest({ + url: '/v1/mall/customPrint', + method: 'put', + }) +} + +/** + * 新建自定义码单 + * @returns + */ +export const CreateCustomCodeApi = () => { + return useRequest({ + url: '/v1/mall/customPrint/add', + method: 'post', + }) +} + +/** + * 计算合计信息 + * @returns + */ +export const CustomPrintCalculationApi = () => { + return useRequest({ + url: '/v1/mall/customPrint/calculation', + method: 'post', + }) +} diff --git a/src/common/constant.ts b/src/common/constant.ts index 5126f35..ea8ac88 100644 --- a/src/common/constant.ts +++ b/src/common/constant.ts @@ -5,11 +5,11 @@ // export const BASE_URL = `http://192.168.0.89:40001/lymarket` // export const BASE_URL = `http://192.168.1.165:40001/lymarket` // 王霞 // export const BASE_URL = 'https://test.zzfzyc.com/lymarket' // 测试环境 -export const BASE_URL = 'https://pre.zzfzyc.com/lymarket' // 预发布 +// export const BASE_URL = 'https://pre.zzfzyc.com/lymarket' // 预发布 // export const BASE_URL = `http://192.168.1.9:40001/lymarket` // 发 // export const BASE_URL = `http://192.168.1.9:50005/lymarket` // 发 // export const BASE_URL = `http://192.168.1.30:50001/lymarket` // 发 -// export const BASE_URL = `https://dev.zzfzyc.com/lymarket` // 开发环境 +// export const BASE_URL = 'https://dev.zzfzyc.com/lymarket' // 开发环境 // export const BASE_URL = 'https://www.zzfzyc.com/lymarket' // 正式环境 // export const BASE_URL = `http://192.168.1.5:40001/lymarket` // 王霞 // export const BASE_URL = 'http://192.168.1.7:50002/lymarket' // 添 diff --git a/src/common/enum.ts b/src/common/enum.ts index fbdca02..0f7a3fc 100644 --- a/src/common/enum.ts +++ b/src/common/enum.ts @@ -70,3 +70,11 @@ export const REFUND_STATUS_ORDER = { ReturnApplyOrderTypeReturnForRefund: { value: 1, label: '退货退款' }, // 退货退款 ReturnApplyOrderTypeSalesRefund: { value: 3, label: '销售退款' }, // 销售退款 } + +// 码单调整枚举 +export const Adjust_Type = { + AdjustTypeAllAdjustType: { value: 1, label: '整单调整' }, + AdjustTypeProductAdjustType: { value: 2, label: '按面料调整' }, + AdjustTypeProductColor: { value: 3, label: '按色号调整' }, +} +export type adjustType = 1 | 2 | 3 diff --git a/src/common/util.ts b/src/common/util.ts index 30dbeeb..7233f42 100644 --- a/src/common/util.ts +++ b/src/common/util.ts @@ -1,3 +1,4 @@ +import type { SelectorQuery } from '@tarojs/taro' import Taro from '@tarojs/taro' import { formatImgUrl } from './fotmat' import { analysisShortCodeApi } from './shortCode' @@ -149,3 +150,26 @@ export const shareShop = () => { } } } + +function delay(delayTime = 25): Promise { + return new Promise((resolve) => { + setTimeout(() => { + // @ts-expect-error no error + resolve() + }, delayTime) + }) +} + +export function delayQuerySelector(selectorStr: string, delayTime = 500): Promise { + return new Promise((resolve) => { + const selector: SelectorQuery = Taro.createSelectorQuery() + delay(delayTime).then(() => { + selector + .select(selectorStr) + .boundingClientRect() + .exec((res: any[]) => { + resolve(res) + }) + }) + }) +} diff --git a/src/components/calendar/body/index.tsx b/src/components/calendar/body/index.tsx new file mode 100644 index 0000000..c091f98 --- /dev/null +++ b/src/components/calendar/body/index.tsx @@ -0,0 +1,365 @@ +import { Swiper, SwiperItem, View } from '@tarojs/components' +import classnames from 'classnames' +import dayjs from 'dayjs' +import React from 'react' +import type { + BaseEventOrig, + ITouch, + ITouchEvent, +} from '@tarojs/components/types/common' +import type { + AtCalendarBodyListGroup, + AtCalendarBodyProps, + AtCalendarBodyState, + Calendar, +} from '../../../types/calendar' +import generateCalendarGroup from '../common/helper' +import AtCalendarDateList from '../ui/date-list/index' +import AtCalendarDayList from '../ui/day-list/index' +import { delayQuerySelector } from '@/common/util' + +const ANIMTE_DURATION = 300 + +const defaultProps: Partial = { + marks: [], + selectedDate: { + end: Date.now(), + start: Date.now(), + }, + format: 'YYYY/MM/DD', + generateDate: Date.now(), +} + +export default class AtCalendarBody extends React.Component< +AtCalendarBodyProps, +Readonly +> { + static defaultProps: Partial = defaultProps + + public constructor(props: AtCalendarBodyProps) { + super(props) + const { + validDates, + marks, + format, + minDate, + maxDate, + generateDate, + selectedDate, + selectedDates, + } = props + + this.generateFunc = generateCalendarGroup({ + validDates, + format, + minDate, + maxDate, + marks, + selectedDates, + }) + const listGroup = this.getGroups(generateDate, selectedDate) + + this.state = { + listGroup, + offsetSize: 0, + isAnimate: false, + } + } + + public componentDidMount(): void { + delayQuerySelector('.at-calendar-slider__main').then((res) => { + this.maxWidth = res[0].width + }) + } + + public UNSAFE_componentWillReceiveProps( + nextProps: AtCalendarBodyProps, + ): void { + const { + validDates, + marks, + format, + minDate, + maxDate, + generateDate, + selectedDate, + selectedDates, + } = nextProps + + this.generateFunc = generateCalendarGroup({ + validDates, + format, + minDate, + maxDate, + marks, + selectedDates, + }) + const listGroup = this.getGroups(generateDate, selectedDate) + + this.setState({ + offsetSize: 0, + listGroup, + }) + } + + private changeCount = 0 + private currentSwiperIndex = 1 + private startX = 0 + private swipeStartPoint = 0 + private isPreMonth = false + private maxWidth = 0 + private isTouching = false + + private generateFunc: ( + generateDate: number, + selectedDate: Calendar.SelectedDate, + isShowStatus?: boolean + ) => Calendar.ListInfo + + private getGroups = ( + generateDate: number, + selectedDate: Calendar.SelectedDate, + ): AtCalendarBodyListGroup => { + const dayjsDate = dayjs(generateDate) + const arr: AtCalendarBodyListGroup = [] + const preList: Calendar.ListInfo = this.generateFunc( + dayjsDate.subtract(1, 'month').valueOf(), + selectedDate, + ) + + const nowList: Calendar.ListInfo = this.generateFunc( + generateDate, + selectedDate, + true, + ) + + const nextList: Calendar.ListInfo = this.generateFunc( + dayjsDate.add(1, 'month').valueOf(), + selectedDate, + ) + + const preListIndex + = this.currentSwiperIndex === 0 ? 2 : this.currentSwiperIndex - 1 + const nextListIndex + = this.currentSwiperIndex === 2 ? 0 : this.currentSwiperIndex + 1 + + arr[preListIndex] = preList + arr[nextListIndex] = nextList + arr[this.currentSwiperIndex] = nowList + + return arr + } + + private handleTouchStart = (e: ITouchEvent): void => { + if (!this.props.isSwiper) { + return + } + this.isTouching = true + this.startX = e.touches[0].clientX + } + + private handleTouchMove = (e: ITouchEvent): void => { + if (!this.props.isSwiper) { + return + } + if (!this.isTouching) { return } + + const { clientX } = e.touches[0] + const offsetSize = clientX - this.startX + + this.setState({ + offsetSize, + }) + } + + private animateMoveSlide = (offset: number, callback?: Function): void => { + this.setState( + { + isAnimate: true, + }, + () => { + this.setState({ + offsetSize: offset, + }) + setTimeout(() => { + this.setState( + { + isAnimate: false, + }, + () => { + callback && callback() + }, + ) + }, ANIMTE_DURATION) + }, + ) + } + + private handleTouchEnd = (): void => { + if (!this.props.isSwiper) { + return + } + + const { offsetSize } = this.state + + this.isTouching = false + const isRight = offsetSize > 0 + + const breakpoint = this.maxWidth / 2 + const absOffsetSize = Math.abs(offsetSize) + + if (absOffsetSize > breakpoint) { + const res = isRight ? this.maxWidth : -this.maxWidth + return this.animateMoveSlide(res, () => { + this.props.onSwipeMonth(isRight ? -1 : 1) + }) + } + this.animateMoveSlide(0) + } + + private handleChange = ( + e: BaseEventOrig<{ + current: number + source: string + }>, + ): void => { + const { current, source } = e.detail + + if (source === 'touch') { + this.currentSwiperIndex = current + this.changeCount += 1 + } + } + + private handleAnimateFinish = (): void => { + if (this.changeCount > 0) { + this.props.onSwipeMonth( + this.isPreMonth ? -this.changeCount : this.changeCount, + ) + this.changeCount = 0 + } + } + + private handleSwipeTouchStart = ( + e: ITouchEvent & { changedTouches: Array }, + ): void => { + const { clientY, clientX } = e.changedTouches[0] + this.swipeStartPoint = this.props.isVertical ? clientY : clientX + } + + private handleSwipeTouchEnd = ( + e: ITouchEvent & { changedTouches: Array }, + ): void => { + const { clientY, clientX } = e.changedTouches[0] + this.isPreMonth = this.props.isVertical + ? clientY - this.swipeStartPoint > 0 + : clientX - this.swipeStartPoint > 0 + } + + public render(): JSX.Element { + const { isSwiper } = this.props + const { isAnimate, offsetSize, listGroup } = this.state + + if (!isSwiper) { + return ( + + + + + + + + + ) + } + + /* 需要 Taro 组件库维护 Swiper 使 小程序 和 H5 的表现保持一致 */ + if (process.env.TARO_ENV === 'h5') { + return ( + + + + + + + + + + + + + + + ) + } + + return ( + + + + {listGroup.map((item, key) => ( + + + + ))} + + + ) + } +} diff --git a/src/components/calendar/common/constant.ts b/src/components/calendar/common/constant.ts new file mode 100644 index 0000000..237d035 --- /dev/null +++ b/src/components/calendar/common/constant.ts @@ -0,0 +1,5 @@ +export const TYPE_PRE_MONTH = -1 + +export const TYPE_NOW_MONTH = 0 + +export const TYPE_NEXT_MONTH = 1 diff --git a/src/components/calendar/common/helper.ts b/src/components/calendar/common/helper.ts new file mode 100644 index 0000000..d5dd45e --- /dev/null +++ b/src/components/calendar/common/helper.ts @@ -0,0 +1,119 @@ +import type { Dayjs } from 'dayjs' +import dayjs from 'dayjs' +import _flow from 'lodash/flow' +import type { Calendar } from '../../../types/calendar' +import * as constant from './constant' +import plugins from './plugins' + +const TOTAL = 7 * 6 + +function getFullItem( + item: Partial, + options: Calendar.GroupOptions, + selectedDate: Calendar.SelectedDate, + isShowStatus?: boolean, +): any { + if (options.marks.find(x => x.value === item.value)) { + (item.marks as Array) = [{ + value: item.value as string, + }] + } + if (!isShowStatus) { return item } + + const bindedPlugins = plugins.map(fn => + fn.bind(null, { + options, + selectedDate, + }), + ) + return _flow(bindedPlugins)(item) +} + +export default function generateCalendarGroup( + options: Calendar.GroupOptions, +): ( + generateDate: number, + selectedDate: Calendar.SelectedDate, + isShowStatus?: boolean + ) => Calendar.ListInfo { + return function( + generateDate: number, + selectedDate: Calendar.SelectedDate, + isShowStatus?: boolean, + ): Calendar.ListInfo { + const date = dayjs(generateDate) + + const { format } = options + + // 获取生成日期的第一天 和 最后一天 + const firstDate = date.startOf('month') + const lastDate = date.endOf('month') + + const preMonthDate = date.subtract(1, 'month') + + const list: Calendar.List = [] + + const nowMonthDays: number = date.daysInMonth() // 获取这个月有多少天 + const preMonthLastDay = preMonthDate.endOf('month').day() // 获取上个月最后一天是周几 + + // 生成上个月的日期 + for (let i = 1; i <= preMonthLastDay + 1; i++) { + const thisDate = firstDate.subtract(i, 'day').startOf('day') + + let item = { + marks: [], + _value: thisDate, + text: thisDate.date(), + type: constant.TYPE_PRE_MONTH, + value: thisDate.format(format), + } + + item = getFullItem(item, options, selectedDate, isShowStatus) + + list.push(item) + } + list.reverse() + + // 生成这个月的日期 + for (let i = 0; i < nowMonthDays; i++) { + const thisDate = firstDate.add(i, 'day').startOf('day') + let item = { + marks: [], + _value: thisDate, + text: thisDate.date(), + type: constant.TYPE_NOW_MONTH, + value: thisDate.format(format), + } + + item = getFullItem(item, options, selectedDate, isShowStatus) + + list.push(item) + } + + // 生成下个月的日期 + let i = 1 + while (list.length < TOTAL) { + const thisDate = lastDate.add(i++, 'day').startOf('day') + let item = { + marks: [], + _value: thisDate, + text: thisDate.date(), + type: constant.TYPE_NEXT_MONTH, + value: thisDate.format(format), + } + + item = getFullItem(item, options, selectedDate, isShowStatus) + + list.push(item) + } + + return { + list, + value: generateDate, + } + } +} + +export function getGenerateDate(date: Calendar.DateArg | undefined): Dayjs { + return dayjs(date).startOf('month') +} diff --git a/src/components/calendar/common/plugins.ts b/src/components/calendar/common/plugins.ts new file mode 100644 index 0000000..47a4473 --- /dev/null +++ b/src/components/calendar/common/plugins.ts @@ -0,0 +1,124 @@ +import dayjs from 'dayjs' +import _isEmpty from 'lodash/isEmpty' +import type { Calendar } from '../../../types/calendar' + +interface PluginArg { + options: Calendar.GroupOptions + + selectedDate: Calendar.SelectedDate +} + +export function handleActive( + args: PluginArg, + item: Calendar.Item, +): Calendar.Item { + const { selectedDate } = args + const { _value } = item + + const { start, end } = selectedDate + + const dayjsEnd = dayjs(end) + const dayjsStart = start ? dayjs(start) : dayjsEnd + + item.isSelected + = _value.isSame(dayjsEnd) + || _value.isSame(dayjsStart) + || (_value.isAfter(dayjsStart) && _value.isBefore(dayjsEnd)) + + item.isSelectedHead = _value.isSame(dayjsStart) + item.isSelectedTail = _value.isSame(dayjsEnd) + + item.isToday = _value.diff(dayjs(Date.now()).startOf('day'), 'day') === 0 + + return item +} + +export function handleMarks( + args: PluginArg, + item: Calendar.Item, +): Calendar.Item { + const { options } = args + const { _value } = item + const { marks } = options + + const markList = marks.filter(mark => + dayjs(mark.value).startOf('day').isSame(_value), + ) + + item.marks = markList.slice(0, 1) + + return item +} + +// export function handleSelectedDates (args: PluginArg): Calendar.Item { +// const { item, options } = args +// const { _value } = item +// const { selectedDates } = options + +// if (selectedDates.length === 0) return args + +// _forEach(selectedDates, date => { +// const { isSelected, isHead, isTail } = item + +// // 如果当前 Item 已经具备了 三种状态下 无需继续判断 跳出循环 +// if (isSelected) { +// return false +// } + +// const { start, end } = date + +// const dayjsEnd = dayjs(end).startOf('day') +// const dayjsStart = dayjs(start).startOf('day') + +// item.isSelected = +// item.isSelected || +// (_value.isAfter(dayjsStart) && _value.isBefore(dayjsEnd)) + +// item.isHead = item.isHead || _value.isSame(dayjsStart) + +// item.isTail = item.isTail || _value.isSame(dayjsEnd) +// }) + +// return item +// } + +export function handleDisabled( + args: PluginArg, + item: Calendar.Item, +): Calendar.Item { + const { options } = args + const { _value } = item + const { minDate, maxDate } = options + + const dayjsMinDate = dayjs(minDate) + const dayjsMaxDate = dayjs(maxDate) + + item.isDisabled + = !!(minDate && _value.isBefore(dayjsMinDate)) + || !!(maxDate && _value.isAfter(dayjsMaxDate)) + + return item +} + +export function handleValid( + args: PluginArg, + item: Calendar.Item, +): Calendar.Item { + const { options } = args + const { _value } = item + const { validDates } = options + + if (!_isEmpty(validDates)) { + const isInclude = validDates.some(date => + dayjs(date.value).startOf('day').isSame(_value), + ) + + item.isDisabled = !isInclude + } + + delete item._value + + return item +} + +export default [handleActive, handleMarks, handleDisabled, handleValid] diff --git a/src/components/calendar/controller/index.tsx b/src/components/calendar/controller/index.tsx new file mode 100644 index 0000000..a575a15 --- /dev/null +++ b/src/components/calendar/controller/index.tsx @@ -0,0 +1,81 @@ +import { Picker, Text, View } from '@tarojs/components' +import classnames from 'classnames' +import type { Dayjs } from 'dayjs' +import dayjs from 'dayjs' +import React from 'react' +import type { + AtCalendarControllerProps, + AtCalendarControllerState, +} from '../../../types/calendar' + +export default class AtCalendarController extends React.Component< +AtCalendarControllerProps, +AtCalendarControllerState +> { + public render(): JSX.Element { + const { + generateDate, + minDate, + maxDate, + monthFormat, + hideArrow, + } = this.props + + const dayjsDate: Dayjs = dayjs(generateDate) + const dayjsMinDate: Dayjs | boolean = !!minDate && dayjs(minDate) + const dayjsMaxDate: Dayjs | boolean = !!maxDate && dayjs(maxDate) + + const isMinMonth: boolean + = dayjsMinDate && dayjsMinDate.startOf('month').isSame(dayjsDate) + + const isMaxMonth: boolean + = dayjsMaxDate && dayjsMaxDate.startOf('month').isSame(dayjsDate) + + const minDateValue: string = dayjsMinDate + ? dayjsMinDate.format('YYYY-MM') + : '' + const maxDateValue: string = dayjsMaxDate + ? dayjsMaxDate.format('YYYY-MM') + : '' + + return ( + + {hideArrow + ? null + : ( + + )} + + + {dayjsDate.format(monthFormat)} + + + {hideArrow + ? null + : ( + + )} + + ) + } +} diff --git a/src/components/calendar/index.scss b/src/components/calendar/index.scss new file mode 100644 index 0000000..7aad719 --- /dev/null +++ b/src/components/calendar/index.scss @@ -0,0 +1,180 @@ + +@import '../../styles/variables/default.scss'; +@import '../../styles/mixins/index.scss'; +.at-calendar { + overflow: hidden; + + /* elements */ + &__header { + .header__flex { + @include display-flex; + @include align-items(center); + + height: 72px; + color: $at-calendar-header-color; + text-align: center; + + &-item { + @include flex(0 0 calc(100% / 7)); + + font-size: 30px; + } + } + } + + &__list { + &.flex { + @include display-flex; + @include align-items(); + @include flex-wrap(wrap); + + color: $at-calendar-day-color; + + .flex__item { + @include flex(0 0 calc(100% / 7)); + + font-size: 30px; + text-align: center; + position: relative; + margin: 5px 0; + + &-container { + @include align-items(center); + @include display-flex; + + width: $at-calendar-day-size; + height: $at-calendar-day-size; + margin-left: auto; + margin-right: auto; + border-radius: 50%; + + .container-text { + @include flex; + } + } + + &-extra { + .extra-marks { + position: absolute; + bottom: 5px; + line-height: 0; + left: 50%; + transform: translateX(-50%); + + .mark { + width: $at-calendar-mark-size; + height: $at-calendar-mark-size; + margin-right: 4px; + display: inline-block; + background-color: $at-calendar-main-color; + border-radius: 50%; + overflow: hidden; + + &:last-child { + margin-right: 0; + } + } + } + } + + &--today { + color: $at-calendar-main-color; + font-weight: bolder; + } + + &--blur { + color: #e1e4e7; + } + + &--selected { + color: white; + background-color: rgba($color: $at-calendar-main-color, $alpha: 1); + + &-head { + border-top-left-radius: 40px; + border-bottom-left-radius: 40px; + } + + &-tail { + border-top-right-radius: 40px; + border-bottom-right-radius: 40px; + } + + /* stylelint-disable-next-line */ + .extra-marks .mark { + background-color: white; + } + + &-head.flex__item--selected-tail { + background-color: transparent; + + .flex__item-container { + background-color: rgba($color: $at-calendar-main-color, + $alpha: 0.7); + } + } + } + } + } + } + + &__controller { + @include display-flex; + @include align-items(center); + @include justify-content(center); + + margin-bottom: 20px; + + .controller__arrow { + @include flex(0 0 40px); + + height: 40px; + border-radius: 12px; + display: inline-block; + background-size: 16px 24px; + background-position: center; + background-color: #f7f8fc; + background-repeat: no-repeat; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAYCAYAAADzoH0MAAAAAXNSR0IArs4c6QAAAnFJREFUOBGVVF1rE0EUnXt3tzFtWmqjKYKfqIhVa1L8FQVRWtwnXwRhidXGDwQf81oCUQMioZRCHwNSgiD4lD9QSYVKsA8KbaW1jbamX8adnWsmMnESbYz7cs6ee8/ZnZm7y9h/Xk/Gs70TE9lOZQNFWsGx1IvDJoozxNDttNpmHOfyTssBj59PHxceP6keREDlYPvBGUMJzTD5LHuKhHtC70EEQe72atMAIoLu0MWzRPxInZnEdxZib2I37L2XEI/HsSvYd44AQrqZIW5b3J8fHR0sS/2ve5DJZIzFFexnSD262QAs+c1js45zyVU6KqIwnU5bS58x0mhGhusbaz153Sw9dW+QSr3yCdwJe4wCKlCigbAWiw7PAYDQdclrAclkxk8+iDBifr3JMq3lO86VQsVMuq549RQSU687mOcNANE+VfiFxuLd6NX3e5llD8qjskqb54E8n24mk5Yf3B6ab2auBsgGC8Q7QOJ1AS6ExrSZ12s6r57CyIi99cNgswywtkkIzDB2eSSdftmuGxp57RgfOfY38HlvRWVNqgmYsDb57sDkZK5hb1RHZQ9+U8bu37S/MtOc0zUg8G2U1yOV4WrTdcXrAqT4MDq0yokXVINEwb32pS9WOJfLmboueW0OGgtP05mj3IXTum6iuXHogDtr27an9D/eQBVijr2AiB/VvUQuePenNXZBfmhKrxEl6Hjv1vAHA2lJ1wRBcH9vf5+cH6k3DZANsei1eWCwIrm6uOf1Jsenq8v7Z4ActFJxrsBMo6gC0GAebPHq/Z6bqJoVyn/EQpGFK08MmF2B/Oj1wZKqtYzxeM5MJKY6dMNPQnnePR8FubkAAAAASUVORK5CYII="); + + &--right { + transform: rotate(180deg); + } + + &--disabled { + opacity: 0.5; + } + } + + .controller__info { + @include flex(0 0 auto); + + font-size: 30px; + margin-left: 40px; + margin-right: 40px; + } + } + } + + .at-calendar-slider__main { + .main__body { + @include display-flex; + + width: 100%; + + &--animate { + transition: transform 300ms cubic-bezier(0.36, 0.66, 0.04, 1); + } + + .body__slider { + @include flex(0 0 100%); + } + } + + &--weapp, + &--swan { + .main__body { + height: 480px; + } + } + } diff --git a/src/components/calendar/index.tsx b/src/components/calendar/index.tsx new file mode 100644 index 0000000..03a1f1e --- /dev/null +++ b/src/components/calendar/index.tsx @@ -0,0 +1,324 @@ +import { View } from '@tarojs/components' +import classnames from 'classnames' +import type { Dayjs } from 'dayjs' +import dayjs from 'dayjs' +import React from 'react' +import type { BaseEventOrig } from '@tarojs/components/types/common' +import type { + AtCalendarDefaultProps, + AtCalendarProps, + AtCalendarPropsWithDefaults, + AtCalendarState, + Calendar, +} from '../../types/calendar' +import AtCalendarBody from './body/index' +import AtCalendarController from './controller/index' +import './index.scss' + +const defaultProps: AtCalendarDefaultProps = { + validDates: [], + marks: [], + isSwiper: true, + hideArrow: false, + isVertical: false, + selectedDates: [], + isMultiSelect: false, + format: 'YYYY/MM/DD', + currentDate: Date.now(), + monthFormat: 'YYYY年MM月', +} + +export default class AtCalendar extends React.Component< +AtCalendarProps, +Readonly +> { + static defaultProps: AtCalendarDefaultProps = defaultProps + + public constructor(props: AtCalendarProps) { + super(props) + + const { currentDate, isMultiSelect } = props as AtCalendarPropsWithDefaults + + this.state = this.getInitializeState(currentDate, isMultiSelect) + } + + public UNSAFE_componentWillReceiveProps(nextProps: AtCalendarProps): void { + const { currentDate, isMultiSelect } = nextProps + if (!currentDate || currentDate === this.props.currentDate) { return } + + if (isMultiSelect && this.props.isMultiSelect) { + const { start, end } = currentDate as Calendar.SelectedDate + const { start: preStart, end: preEnd } = this.props + .currentDate as Calendar.SelectedDate + + if (start === preStart && preEnd === end) { + return + } + } + + const stateValue: AtCalendarState = this.getInitializeState( + currentDate, + isMultiSelect, + ) + + this.setState(stateValue) + } + + private getSingleSelectdState = (value: Dayjs): Partial => { + const { generateDate } = this.state + + const stateValue: Partial = { + selectedDate: this.getSelectedDate(value.valueOf()), + } + + const dayjsGenerateDate: Dayjs = value.startOf('month') + const generateDateValue: number = dayjsGenerateDate.valueOf() + + if (generateDateValue !== generateDate) { + this.triggerChangeDate(dayjsGenerateDate) + stateValue.generateDate = generateDateValue + } + + return stateValue + } + + private getMultiSelectedState = ( + value: Dayjs, + ): Pick => { + const { selectedDate } = this.state + const { end, start } = selectedDate + + const valueUnix: number = value.valueOf() + const state: Pick = { + selectedDate, + } + + if (end) { + state.selectedDate = this.getSelectedDate(valueUnix, 0) + } + else { + state.selectedDate.end = Math.max(valueUnix, +start) + state.selectedDate.start = Math.min(valueUnix, +start) + } + + return state + } + + private getSelectedDate = ( + start: number, + end?: number, + ): Calendar.SelectedDate => { + const stateValue: Calendar.SelectedDate = { + start, + end: start, + } + + if (typeof end !== 'undefined') { + stateValue.end = end + } + + return stateValue + } + + private getInitializeState( + currentDate: Calendar.DateArg | Calendar.SelectedDate, + isMultiSelect?: boolean, + ): AtCalendarState { + let end: number + let start: number + let generateDateValue: number + + if (!currentDate) { + const dayjsStart = dayjs() + start = dayjsStart.startOf('day').valueOf() + generateDateValue = dayjsStart.startOf('month').valueOf() + return { + generateDate: generateDateValue, + selectedDate: { + start: '', + }, + } + } + + if (isMultiSelect) { + const { start: cStart, end: cEnd } = currentDate as Calendar.SelectedDate + + const dayjsStart = dayjs(cStart) + + start = dayjsStart.startOf('day').valueOf() + generateDateValue = dayjsStart.startOf('month').valueOf() + + end = cEnd ? dayjs(cEnd).startOf('day').valueOf() : start + } + else { + const dayjsStart = dayjs(currentDate as Calendar.DateArg) + + start = dayjsStart.startOf('day').valueOf() + generateDateValue = dayjsStart.startOf('month').valueOf() + + end = start + } + + return { + generateDate: generateDateValue, + selectedDate: this.getSelectedDate(start, end), + } + } + + private triggerChangeDate = (value: Dayjs): void => { + const { format } = this.props + + if (typeof this.props.onMonthChange !== 'function') { return } + + this.props.onMonthChange(value.format(format)) + } + + private setMonth = (vectorCount: number): void => { + const { format } = this.props + const { generateDate } = this.state + + const _generateDate: Dayjs = dayjs(generateDate).add(vectorCount, 'month') + this.setState({ + generateDate: _generateDate.valueOf(), + }) + + if (vectorCount && typeof this.props.onMonthChange === 'function') { + this.props.onMonthChange(_generateDate.format(format)) + } + } + + private handleClickPreMonth = (isMinMonth?: boolean): void => { + if (isMinMonth === true) { + return + } + + this.setMonth(-1) + + if (typeof this.props.onClickPreMonth === 'function') { + this.props.onClickPreMonth() + } + } + + private handleClickNextMonth = (isMaxMonth?: boolean): void => { + if (isMaxMonth === true) { + return + } + + this.setMonth(1) + + if (typeof this.props.onClickNextMonth === 'function') { + this.props.onClickNextMonth() + } + } + + // picker 选择时间改变时触发 + private handleSelectDate = (e: BaseEventOrig<{ value: string }>): void => { + const { value } = e.detail + + const _generateDate: Dayjs = dayjs(value) + const _generateDateValue: number = _generateDate.valueOf() + + if (this.state.generateDate === _generateDateValue) { return } + + this.triggerChangeDate(_generateDate) + this.setState({ + generateDate: _generateDateValue, + }) + } + + private handleDayClick = (item: Calendar.Item): void => { + const { isMultiSelect } = this.props + const { isDisabled, value } = item + + if (isDisabled) { return } + + const dayjsDate: Dayjs = dayjs(value) + + let stateValue: Partial = {} + + if (isMultiSelect) { + stateValue = this.getMultiSelectedState(dayjsDate) + } + else { + stateValue = this.getSingleSelectdState(dayjsDate) + } + + this.setState(stateValue as AtCalendarState, () => { + this.handleSelectedDate() + }) + + if (typeof this.props.onDayClick === 'function') { + this.props.onDayClick({ value: item.value }) + } + } + + private handleSelectedDate = (): void => { + const selectDate = this.state.selectedDate + if (typeof this.props.onSelectDate === 'function') { + const info: Calendar.SelectedDate = { + start: dayjs(selectDate.start).format(this.props.format), + } + + if (selectDate.end) { + info.end = dayjs(selectDate.end).format(this.props.format) + } + + this.props.onSelectDate({ + value: info, + }) + } + } + + private handleDayLongClick = (item: Calendar.Item): void => { + if (typeof this.props.onDayLongClick === 'function') { + this.props.onDayLongClick({ value: item.value }) + } + } + + public render(): JSX.Element { + const { generateDate, selectedDate } = this.state + const { + validDates, + marks, + format, + minDate, + maxDate, + isSwiper, + className, + hideArrow, + isVertical, + monthFormat, + selectedDates, + } = this.props as AtCalendarPropsWithDefaults + + return ( + + + + + ) + } +} diff --git a/src/components/calendar/types/calendar.d.ts b/src/components/calendar/types/calendar.d.ts new file mode 100644 index 0000000..548af63 --- /dev/null +++ b/src/components/calendar/types/calendar.d.ts @@ -0,0 +1,225 @@ +import type dayjs from 'dayjs' +// import { BaseEvent } from '@tarojs/components/types/common' + +// #region Calendar +declare namespace Calendar { + export type DateArg = string | number | Date + + export type classNameType = + | string + | Array + | Record + + export interface Mark { + value: DateArg + } + + export interface ValidDate { + value: DateArg + } + + export interface Item { + value: string + + _value: dayjs.Dayjs + + text: number + + type: number + + marks: Array + + isActive?: boolean + + isToday?: boolean + + isBeforeMin?: boolean + + isAfterMax?: boolean + + isDisabled?: boolean + + isSelected?: boolean + + isSelectedHead?: boolean + + isSelectedTail?: boolean + } + + export interface GroupOptions { + validDates: Array + + marks: Array + + format: string + + selectedDates: Array + + minDate?: DateArg + + maxDate?: DateArg + } + + export type List = Array + + export interface ListInfo { + value: number + + list: List + } + + export interface SelectedDate { + end?: Calendar.DateArg + + start: Calendar.DateArg + } +} + +export default Calendar +export { Calendar } +// #endregion + +// #region AtCalendar +export interface AtCalendarPropsBase { + format?: string + + validDates?: Array + + minDate?: Calendar.DateArg + + maxDate?: Calendar.DateArg + + isSwiper?: boolean + + marks?: Array + + monthFormat?: string + + hideArrow?: boolean + + isVertical?: boolean + + className?: Calendar.classNameType + + onClickPreMonth?: () => void + + onClickNextMonth?: () => void + + onSelectDate?: (item: { value: Calendar.SelectedDate }) => void + + onDayClick?: (item: { value: string }) => void + + onDayLongClick?: (item: { value: string }) => void + + onMonthChange?: (value: string) => void +} + +export interface AtCalendarSingleSelectedProps extends AtCalendarPropsBase { + isMultiSelect?: false + + currentDate?: Calendar.DateArg +} + +export interface AtCalendarMutilSelectedProps extends AtCalendarPropsBase { + isMultiSelect?: true + + currentDate?: Calendar.SelectedDate +} + +export type AtCalendarProps = + | AtCalendarSingleSelectedProps + | AtCalendarMutilSelectedProps + +export interface AtCalendarDefaultProps { + format: string + + isSwiper: boolean + + validDates: Array + + marks: Array + + currentDate: Calendar.DateArg | Calendar.SelectedDate + + monthFormat: string + + hideArrow: boolean + + isVertical: boolean + + isMultiSelect: boolean + + selectedDates: Array +} + +export interface AtCalendarState { + generateDate: number + + selectedDate: Calendar.SelectedDate +} + +export type AtCalendarPropsWithDefaults = AtCalendarProps & +AtCalendarDefaultProps +// #endregion + +// #region AtCalendarController +export interface AtCalendarControllerProps { + generateDate: Calendar.DateArg + + minDate?: Calendar.DateArg + + maxDate?: Calendar.DateArg + + hideArrow: boolean + + monthFormat: string + + onPreMonth: () => void + + onNextMonth: () => void + + onSelectDate: (e: any) => void +} + +export interface AtCalendarControllerState {} +// #endregion + +// #region AtCalendarBody +export type AtCalendarBodyListGroup = Array> + +export interface AtCalendarBodyProps { + format: string + + validDates: Array + + marks: Array + + isSwiper: boolean + + minDate?: Calendar.DateArg + + maxDate?: Calendar.DateArg + + isVertical: boolean + + generateDate: number + + selectedDate: Calendar.SelectedDate + + selectedDates: Array | [] + + onDayClick: (item: Calendar.Item) => void + + onSwipeMonth: (vectorCount: number) => void + + onLongClick: (item: Calendar.Item) => void +} + +export interface AtCalendarBodyState { + isAnimate: boolean + + offsetSize: number + + listGroup: AtCalendarBodyListGroup +} +// #endregion diff --git a/src/components/calendar/ui/date-list/index.tsx b/src/components/calendar/ui/date-list/index.tsx new file mode 100644 index 0000000..f421331 --- /dev/null +++ b/src/components/calendar/ui/date-list/index.tsx @@ -0,0 +1,82 @@ +import { Text, View } from '@tarojs/components' +import classnames from 'classnames' +import React from 'react' +import type { Calendar } from '../../types/calendar' +import * as constant from '../../common/constant' + +const MAP: Record = { + [constant.TYPE_PRE_MONTH]: 'pre', + [constant.TYPE_NOW_MONTH]: 'now', + [constant.TYPE_NEXT_MONTH]: 'next', +} + +export interface Props { + list: Calendar.List + + onClick?: (item: Calendar.Item) => void + + onLongClick?: (item: Calendar.Item) => void +} + +export default class AtCalendarList extends React.Component { + private handleClick = (item: Calendar.Item): void => { + if (typeof this.props.onClick === 'function') { + this.props.onClick(item) + } + } + + private handleLongClick = (item: Calendar.Item): void => { + if (typeof this.props.onLongClick === 'function') { + this.props.onLongClick(item) + } + } + + public render(): JSX.Element | null { + const { list } = this.props + if (!list || list.length === 0) { return null } + + return ( + + {list.map((item: Calendar.Item) => ( + + + {item.text} + + + {item.marks && item.marks.length > 0 + ? ( + + {item.marks.map((mark, key) => ( + + {mark.value as React.ReactNode} + + ))} + + ) + : null} + + + ))} + + ) + } +} diff --git a/src/components/calendar/ui/day-list/index.tsx b/src/components/calendar/ui/day-list/index.tsx new file mode 100644 index 0000000..f6b4f83 --- /dev/null +++ b/src/components/calendar/ui/day-list/index.tsx @@ -0,0 +1,20 @@ +import { View } from '@tarojs/components' +import React from 'react' + +export default class AtCalendarHeader extends React.Component { + public render(): JSX.Element { + return ( + + + + + + + + + + + + ) + } +} diff --git a/src/components/codeSelect/index.tsx b/src/components/codeSelect/index.tsx index 15d13c5..0e774c2 100644 --- a/src/components/codeSelect/index.tsx +++ b/src/components/codeSelect/index.tsx @@ -8,16 +8,26 @@ import ViewCodeList from '@/components/viewCodeList/index' interface param { y: number + custom_print_id: number + sale_order_id: number + orderObj?: any } -export default ({ y, orderObj = {} }: param) => { +export default ({ y, custom_print_id = 0, sale_order_id = 0, orderObj = {} }: param) => { const [screenHeight, setScreenHeight] = useState({ customer_service_y: 0, code_list_y: 0, }) const [showCode, setShowCode] = useState(false) - const [showPopup, setshowPopup] = useState(false) + const onNavigateTo = () => { + if (custom_print_id) { + goLink(`/pages/codeSetting/index?custom_print_id=${custom_print_id}`) + } + else { + goLink(`/pages/codeSetting/index?sale_order_id=${sale_order_id}`) + } + } return (<> {showCode && setShowCode(!showCode)}>} @@ -31,9 +41,9 @@ export default ({ y, orderObj = {} }: param) => { 自定义码单预览 - goLink('/pages/codeSetting/index')}> + - 编辑自定义码单 + {custom_print_id ? '编辑自定义码单' : '新建自定义码单'} } setShowCode(!showCode)}>码单 diff --git a/src/components/moveBtn/index.tsx b/src/components/moveBtn/index.tsx index 8df39a9..3da2ac1 100644 --- a/src/components/moveBtn/index.tsx +++ b/src/components/moveBtn/index.tsx @@ -21,8 +21,9 @@ interface param { messagePath?: string showCart?: false|true orderObj?: any + orderInfo?: any } -const MoveBtn = ({ orderObj = {}, children = null, onShopClick, showList = [], messageTitle = '', messagePath = '', showCart = false }: param) => { +const MoveBtn = ({ orderObj = {}, children = null, onShopClick, showList = [], messageTitle = '', messagePath = '', showCart = false, orderInfo = {} }: param) => { const userInfo = useSelector(state => state.userInfo) // 获取购物车数据数量 const { getShopCount, commonData } = useCommonData() @@ -102,7 +103,7 @@ const MoveBtn = ({ orderObj = {}, children = null, onShopClick, showList = [], m > } - {onShow('code') && } + {onShow('code') && } ) diff --git a/src/components/popupModal/index.module.scss b/src/components/popupModal/index.module.scss new file mode 100644 index 0000000..207723b --- /dev/null +++ b/src/components/popupModal/index.module.scss @@ -0,0 +1,74 @@ +.popup_modal_main { + position: fixed; + display: flex; + align-items: center; + justify-content: center; + width: 100vw; + height: 100vh; + top: 0; + left: 0; + z-index: 1000; + .popup_modal_con { + background-color: #fff; + border-radius: 16px; + width: 606px; + z-index: 1000; + .popup_modal_title { + height: 112px; + background: #ffffff; + border-radius: 16px 16px 0px 0px; + font-size: 32px; + color: #333333; + text-align: center; + line-height: 112px; + } + .popup_modal_input { + height: 144px; + background: #ffffff; + display: flex; + justify-content: center; + .input { + width: 526px; + height: 88px; + background: #f5f5f5; + padding: 20px; + border: 1px solid #337fff; + border-radius: 16px; + box-sizing: border-box; + } + input { + background: #f5f5f5; + } + } + .popup_modal_btn { + display: flex; + width: 606px; + height: 112px; + background: #ffffff; + border-radius: 0px 0px 16px 16px; + border-top: 1px solid rgba(0, 0, 0, 0.1); + .popup_modal_btn_item { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + &:nth-child(1) { + color: #333333; + border-right: 1px solid rgba(0, 0, 0, 0.1); + } + &:nth-child(2) { + color: #337fffff; + } + } + } + } + .mask { + position: absolute; + width: 100%; + height: 100%; + left: 0; + top: 0; + background: rgba($color: #000000, $alpha: 0.6); + z-index: 999; + } +} diff --git a/src/components/popupModal/index.tsx b/src/components/popupModal/index.tsx new file mode 100644 index 0000000..e4d34f4 --- /dev/null +++ b/src/components/popupModal/index.tsx @@ -0,0 +1,59 @@ +import { Input, View } from '@tarojs/components' +import { useEffect, useState } from 'react' +import styles from './index.module.scss' + +export interface Param { + show: boolean + title: string + onConfirm?: (val: string) => void + onCancel?: () => void + defaultValue?: string + onClose?: () => void +} +export default (props: Param) => { + const { show = false, title = '', onConfirm, onCancel, defaultValue = '', onClose } = props + const [value, setValue] = useState('') + const [openStatus, setOpenStatus] = useState(false) + useEffect(() => { + if (value !== defaultValue) { setValue(() => defaultValue) } + }, [defaultValue]) + useEffect(() => { + if (show !== openStatus) { setOpenStatus(() => show) } + }, [show]) + + const onInputEven = (e) => { + const res = e.detail.value + setValue(res) + } + const onCancelEven = () => { + onCancel?.() + onCloseEven() + } + const onCloseEven = () => { + onClose?.() + setOpenStatus(false) + } + const onConfirmEven = (val) => { + onClose?.() + onConfirm?.(val) + } + return ( + <> + {openStatus && + + {title} + + + + + + + 取消 + onConfirmEven(value)}>确认修改 + + + + } + + ) +} diff --git a/src/components/timePicker/index.module.scss b/src/components/timePicker/index.module.scss new file mode 100644 index 0000000..e59600b --- /dev/null +++ b/src/components/timePicker/index.module.scss @@ -0,0 +1,12 @@ + + +.time-box { + padding: 40px; +} + +.sure-box { + margin-left: 102px; + margin-right: 102px; + font-size: 28px; + font-weight: 500; +} diff --git a/src/components/timePicker/index.tsx b/src/components/timePicker/index.tsx new file mode 100644 index 0000000..2497dbd --- /dev/null +++ b/src/components/timePicker/index.tsx @@ -0,0 +1,55 @@ +import { View } from '@tarojs/components' +import { memo, useState } from 'react' +import dayjs from 'dayjs' +import NormalButton from '../normalButton' +import styles from './index.module.scss' +import AtCalendar from '@/components/calendar/index' +import Popup from '@/components/popup' + +type DateArg = string | number | Date +interface Props { + end?: DateArg + start?: DateArg + onSelectDate?: (any) => void +} +const TimePicker = (props: Props) => { + const { start = '', end = '', onSelectDate } = props + const [time, setTime] = useState({}) + + const handTime = (e) => { + const { start, end } = e.value + // 如果选的是同一天的日期, end 自动加一天 + if (!end) { + // 判断如果没选下一天的时候 + e.value.end = `${dayjs(new Date(start)).add(1, 'day').format('YYYY-MM-DD')} 00:00:00` + } + else + if (start === end) { + e.value.end = `${dayjs(new Date(start)).add(1, 'day').format('YYYY-MM-DD')} 00:00:00` + } + else { + e.value.start = `${dayjs(start).format('YYYY-MM-DD')} 00:00:00` + e.value.end = `${dayjs(end).format('YYYY-MM-DD')} 00:00:00` + } + console.log('e===>', e) + setTime(e) + } + // 由于小程序的bug,部分ios和安卓显示时间的时候会有问题,原因是格式化时有`-`这个横杠 + return ( + <> + + handTime(e)} + /> + + onSelectDate?.(time)} size="normal" round customClassName={styles['sure-box']}>确认 + + ) +} +export default memo(TimePicker) diff --git a/src/components/timePickerPopup/index.scss b/src/components/timePickerPopup/index.scss new file mode 100644 index 0000000..b808aa6 --- /dev/null +++ b/src/components/timePickerPopup/index.scss @@ -0,0 +1,19 @@ + + +.time-box { + padding: 40px; +} + +.sure-box { + // padding: 16px 102px 30px 102px; + margin-left: 102px; + margin-right: 102px; + height: 80px; + background: #337FFF; + border-radius: 44px; + font-size: 28px; + font-weight: 500; + color: #FFFFFF; + text-align: center; + line-height: 80px; +} diff --git a/src/components/timePickerPopup/index.tsx b/src/components/timePickerPopup/index.tsx new file mode 100644 index 0000000..7b53258 --- /dev/null +++ b/src/components/timePickerPopup/index.tsx @@ -0,0 +1,23 @@ +import { memo } from 'react' +import './index.scss' +import TimePicker from '../timePicker' +import Popup from '@/components/popup' + +type DateArg = string | number | Date +interface Props { + showTime: boolean + closePopup?: () => void + end?: DateArg + start?: DateArg + onSelectDate?: (any) => void +} +const TimePickerPopup = (props: Props) => { + const { showTime = false, closePopup, start = '', end = '', onSelectDate } = props + + return ( + closePopup?.()}> + + + ) +} +export default memo(TimePickerPopup) diff --git a/src/context/ContextCodeSetting/index.tsx b/src/context/ContextCodeSetting/index.tsx new file mode 100644 index 0000000..b4b204b --- /dev/null +++ b/src/context/ContextCodeSetting/index.tsx @@ -0,0 +1,135 @@ +import React, { useContext, useReducer } from 'react' +import { CustomPrintCalculationApi } from '@/api/codeManage' + +interface params { + productData?: any + dispatch?: any +} +interface PropsType { + children: React.ReactNode +} + +type ACTIONTYPE = + | { type: 'setInitData'; data: any } + | { type: 'updateData'; data: any } + | { type: 'changeAdjustType'; data: number } + | { type: 'changeSaveStatus'; data: boolean } + +function createCtx() { + const ctx = React.createContext(undefined) + function useCtx() { + const c = useContext(ctx) + if (c === undefined) { throw new Error('useCtx must be inside a Provider with a value') } + return c + } + return [useCtx, ctx.Provider] as const +} +export const [useCurrenCode, CurrentUserProvider] = createCtx() + +export default (props: PropsType) => { + const initialState = { + data: null, // 码单数据 + adjust_type: 1, // 码单调整类型 + custom_print_id: 0, // 自定义码单id + sale_order_id: 0, // 销售码单id + admin_data: null, // 需要传给后端的数据 + save_status: false, // 是否保存了数据 + } + function reducer(state: typeof initialState, action: ACTIONTYPE) { + switch (action.type) { + case 'setInitData': + return onInitData(state, action) + case 'updateData': + return onUpdateData(state, action) + case 'changeAdjustType': + return { ...state, adjust_type: action.data } + case 'changeSaveStatus': + return { ...state, save_status: action.data } + default: + throw new Error('reducer没找到对应的type') + } + } + + // 初始化数据 + const onInitData = (state, action) => { + const { data, custom_print_id, sale_order_id } = action + const custom_order_total = { + total_weight_error: data?.total_weight_error, + total_sale_weight: data?.total_sale_weight, + total_amount: data?.total_amount, + } + data.weight_admin = 0 + data.price_admin = 0 + data.weight_error_admin = 0 + data?.product_details?.map((item, index) => { + item.weight_admin = 0 + item.price_admin = 0 + item.weight_error_admin = 0 + item.index_str = index.toString() + return item?.product_color_details?.map((citem, cindex) => { + citem.index_str = `${item.index_str}_${cindex}` // 通过这个可以快速定位数组位置 + citem.weight_setting = citem.weight + citem.weight_error_setting = citem.weight_error + citem.price_setting = citem.price + citem.weight_admin = 0 + citem.price_admin = 0 + citem.weight_error_admin = 0 + return citem + }) + }) + return { + ...state, + data, + custom_print_id, + sale_order_id, + custom_order_total, + admin_data: null, + init_state: true, + } + } + + // 后端所需数据 + const onUpdateData = (state, action) => { + const { data } = action + const updateData = { + adjust_type: parseInt(state.adjust_type), + purchaser_form_title_id: 0, + custom_print_product: [], + price: 0, + weight: 0, + weight_error: 0, + custom_print_id: parseInt(state.custom_print_id!), + sale_order_id: parseInt(state.sale_order_id!), + } + updateData.weight = data?.weight_admin || 0 + updateData.price = data?.price_admin || 0 + updateData.weight_error = data?.weight_error_admin || 0 + data?.product_details?.map((item) => { + const product_item = { + price: item.price_admin || 0, + weight: item.weight_admin || 0, + weight_error: item.weight_error_admin || 0, + product_id: item.product_id, + product_name: item.product_name, + custom_print_product_color: [], + } + item?.product_color_details?.map((citem) => { + product_item.custom_print_product_color.push({ + price: citem.price_admin || 0, + weight: citem.weight_admin || 0, + weight_error: citem.weight_error_admin || 0, + product_color_id: citem.product_color_id, + product_color_name: citem.product_color_name, + }) + }) + updateData.custom_print_product.push(product_item) + }) + return { ...state, admin_data: updateData, data: { ...data } } + } + + const [productData, dispatch] = useReducer(reducer, initialState) + + return ( + + ) +} diff --git a/src/pages/codeList/components/codeModel/index.tsx b/src/pages/codeList/components/codeModel/index.tsx index 3c23449..db164b5 100644 --- a/src/pages/codeList/components/codeModel/index.tsx +++ b/src/pages/codeList/components/codeModel/index.tsx @@ -1,22 +1,46 @@ import { Text, View } from '@tarojs/components' -import { useState } from 'react' +import { useEffect, useState } from 'react' import ColorItem from '../colorItem' import styles from './index.module.scss' import IconFont from '@/components/iconfont/iconfont' import SelectList from '@/components/selectList' import Search from '@/components/search' +import { GetCustomCodeLApi } from '@/api/codeManage' export default () => { + const [formData, setFormData] = useState({ + sale_start_time: '', + sale_end_time: '', + any_query: '', + }) + // 获取码单列表 + const [list, setList] = useState([]) + const { fetchData: getCustomCode } = GetCustomCodeLApi() + const onCustomCode = async() => { + const res = await getCustomCode(formData) + setList(() => res.data?.list) + } + useEffect(() => { + onCustomCode() + }, [formData]) + + const onSearch = (val) => { + setFormData(e => ({ ...e, any_query: val })) + } return - + 日期 - + {list?.map((item) => { + return + + + })} } diff --git a/src/pages/codeList/components/colorItem/index.tsx b/src/pages/codeList/components/colorItem/index.tsx index 6cb2833..7c80091 100644 --- a/src/pages/codeList/components/colorItem/index.tsx +++ b/src/pages/codeList/components/colorItem/index.tsx @@ -1,12 +1,36 @@ import { Text, View } from '@tarojs/components' +import { useMemo } from 'react' import styles from './index.module.scss' import LabAndImg from '@/components/LabAndImg' +import { formatPriceDiv, formatWeightDiv } from '@/common/fotmat' -export default () => { +interface Param { + info: { + purchaser_name: string + purchaser_phone: string + sale_order_no: string + title_name: string + sale_mode: number + product_color_count: number + product_count: number + roll: number + total_amount: number + total_sale_weight: number + sale_mode_name: string + } +} +export default (props: Param) => { + const { info } = props + const product = useMemo(() => { + return { + message: `${formatWeightDiv(info?.total_sale_weight)}kg | ¥${formatPriceDiv(info?.total_amount)}`, + count: `订单信息:共 ${info?.product_count} 种面料,${info?.product_color_count} 种颜色,共 ${info?.roll} 条`, + } + }, [info]) return - 订单号:XS-LY-2208220092 - 大货 + 订单号:{info?.sale_order_no} + {info?.sale_mode_name} @@ -15,19 +39,19 @@ export default () => { 公司抬头: - XL纺织公司 + {info?.title_name} 客户名称: - 上生企业制衣厂 + {info?.purchaser_name} 商品信息: - 106.60kg|¥1,332.00 + {product.message} - 共 2 种面料,3 种颜色,共 4 条 + {product.count} 码单浏览 码单编辑 diff --git a/src/pages/codeList/components/companyModel/index.tsx b/src/pages/codeList/components/companyModel/index.tsx index 2fda695..fe4c139 100644 --- a/src/pages/codeList/components/companyModel/index.tsx +++ b/src/pages/codeList/components/companyModel/index.tsx @@ -1,4 +1,5 @@ import { Text, View } from '@tarojs/components' +import { useDidShow } from '@tarojs/taro' import { useEffect, useState } from 'react' import type { CompanyParam } from '../companyItem' import CompanyItem from '../companyItem' @@ -10,12 +11,12 @@ import { goLink } from '@/common/common' export default () => { const { fetchData } = weightListApi() const [list, setList] = useState([]) - useEffect(() => { + useDidShow(() => { (async() => { const res = await fetchData() setList(() => res.data?.list) })() - }, []) + }) return diff --git a/src/pages/codeList/index.tsx b/src/pages/codeList/index.tsx index 7c81830..e9b7243 100644 --- a/src/pages/codeList/index.tsx +++ b/src/pages/codeList/index.tsx @@ -1,9 +1,11 @@ import { View } from '@tarojs/components' -import { useState } from 'react' +import { useEffect, useState } from 'react' import styles from './index.module.scss' import CodeModel from './components/codeModel' import CompanyModel from './components/companyModel' import SelectList from '@/components/selectList' +import { GetCustomCodeLApi } from '@/api/codeManage' +import TimePickerPopup from '@/components/timePickerPopup' export default () => { const selectList = [ @@ -15,5 +17,6 @@ export default () => { setSelectIndex(index)} /> {selectIndex == 1 && } {selectIndex == 2 && } + {/* */} } diff --git a/src/pages/codeSetting/components/bottomBtn/index.tsx b/src/pages/codeSetting/components/bottomBtn/index.tsx index 89a9541..fc9c354 100644 --- a/src/pages/codeSetting/components/bottomBtn/index.tsx +++ b/src/pages/codeSetting/components/bottomBtn/index.tsx @@ -1,12 +1,17 @@ import { View } from '@tarojs/components' import styles from './index.module.scss' -export default () => { +export type BottomItem = 'del'|'preview'|'save' +interface Param { + onClick?: (val: BottomItem) => void +} +export default (props: Param) => { + const { onClick } = props return - 删除码单 - 预览码单 - 保存码单 + onClick?.('del')}>删除码单 + onClick?.('preview')}>预览码单 + onClick?.('save')}>保存码单 diff --git a/src/pages/codeSetting/components/colorItemSetting/index.tsx b/src/pages/codeSetting/components/colorItemSetting/index.tsx index 85a7f91..5b6d4b6 100644 --- a/src/pages/codeSetting/components/colorItemSetting/index.tsx +++ b/src/pages/codeSetting/components/colorItemSetting/index.tsx @@ -15,8 +15,8 @@ export default () => { 大货 {new Array(5).fill('').map((item, index) => - - + + {/* */} )} diff --git a/src/pages/codeSetting/components/colorSetting/index.module.scss b/src/pages/codeSetting/components/colorSetting/index.module.scss index a66a67f..e3b5813 100644 --- a/src/pages/codeSetting/components/colorSetting/index.module.scss +++ b/src/pages/codeSetting/components/colorSetting/index.module.scss @@ -5,39 +5,4 @@ margin-top: 24px; padding: 0 32px 32px 32px; box-sizing: border-box; - .product_list__item { - .product_list__item--title { - height: 82px; - font-size: 28px; - display: flex; - justify-content: space-between; - color: #000000; - align-items: center; - border-bottom: 1px solid rgba(0, 0, 0, 0.1); - .product_title { - margin-right: 8px; - } - .mode_status { - width: 60px; - height: 30px; - font-size: 20px; - background: #337fff; - border-radius: 8px; - text-align: center; - line-height: 30px; - color: #fff; - margin-left: 8px; - } - .con { - display: flex; - align-items: center; - } - .update { - display: flex; - align-items: center; - color: #337fffff; - font-size: 28px; - } - } - } } diff --git a/src/pages/codeSetting/components/colorSetting/index.tsx b/src/pages/codeSetting/components/colorSetting/index.tsx index 8462fd9..cbafaed 100644 --- a/src/pages/codeSetting/components/colorSetting/index.tsx +++ b/src/pages/codeSetting/components/colorSetting/index.tsx @@ -1,27 +1,27 @@ import { Text, View } from '@tarojs/components' +import { memo, useCallback, useMemo, useState } from 'react' +import classNames from 'classnames' import ProductItem from '../productItem' import styles from './index.module.scss' +import ProductBlock from './productBlock' import IconFont from '@/components/iconfont/iconfont' import LabAndImg from '@/components/LabAndImg' import { goLink } from '@/common/common' -export default () => { +interface Parma { + orderData: any +} +export default memo((props: Parma) => { + const { orderData = {} } = props + const productList = useMemo(() => { + return orderData?.product_details || [] + }, [orderData]) return <> - - - - 5215# 26S双纱亲水滑爽棉 - - 大货 - - goLink('/pages/codeSetting/codeColorList/index')}> - 编辑 - - - - {new Array(5).fill('').map((item, index) => )} - + {productList?.map((item) => { + return + })} + -} +}) diff --git a/src/pages/codeSetting/components/colorSetting/productBlock/index.module.scss b/src/pages/codeSetting/components/colorSetting/productBlock/index.module.scss new file mode 100644 index 0000000..3da8649 --- /dev/null +++ b/src/pages/codeSetting/components/colorSetting/productBlock/index.module.scss @@ -0,0 +1,54 @@ +.product_list__item { + .product_list__item--title { + height: 82px; + font-size: 28px; + display: flex; + justify-content: space-between; + color: #000000; + align-items: center; + border-bottom: 1px solid rgba(0, 0, 0, 0.1); + .product_title { + margin-right: 8px; + } + .mode_status { + width: 60px; + height: 30px; + font-size: 20px; + background: #337fff; + border-radius: 8px; + text-align: center; + line-height: 30px; + color: #fff; + margin-left: 8px; + } + .con { + display: flex; + align-items: center; + } + .update { + display: flex; + align-items: center; + color: #337fffff; + font-size: 28px; + } + } + .product_list__item--con { + transition: height 0.3s ease-in-out; + overflow: hidden; + } + .open_up_icon { + transform: rotate(180deg); + } + .close_up_icon { + transform: rotate(0); + } + .up_btn { + width: 100%; + height: 72px; + display: flex; + justify-content: center; + align-items: center; + font-size: 28px; + color: rgba(0, 0, 0, 0.4); + } +} diff --git a/src/pages/codeSetting/components/colorSetting/productBlock/index.tsx b/src/pages/codeSetting/components/colorSetting/productBlock/index.tsx new file mode 100644 index 0000000..46c05b8 --- /dev/null +++ b/src/pages/codeSetting/components/colorSetting/productBlock/index.tsx @@ -0,0 +1,69 @@ +import { Text, View } from '@tarojs/components' +import { memo, useCallback, useContext, useState } from 'react' +import classNames from 'classnames' +import ProductItem from '../../productItem' +import styles from './index.module.scss' +import IconFont from '@/components/iconfont/iconfont' +import PopupModal from '@/components/popupModal' +import { useCurrenCode } from '@/context/ContextCodeSetting' +import { goLink } from '@/common/common' + +interface Parma { + productInfo: any + sale_mode_name: string +} + +type IndexParam = { + onChange: (val: string) => void +} & Parma + +export default memo((props: Parma) => { + const { productInfo } = props + const { dispatch, productData } = useCurrenCode() + const getNewName = useCallback((name) => { + const index = productInfo.index_str.split('_')[0] + productData.data.product_details[index] = { + ...productData.data.product_details[index], + product_name: name, + } + dispatch({ type: 'updateData', data: { ...productData.data } }) + }, [productInfo]) + return <> + + +}) + +const Index = memo((props: IndexParam) => { + const { productInfo, sale_mode_name } = props + const [showEdit, setShowEdit] = useState(false) + const [upStatus, setStatus] = useState(false) + const [title, setTitle] = useState('') + console.log('productInfo内容:::', productInfo) + const onUpdate = () => { + setTitle(productInfo.product_name) + setShowEdit(true) + } + const onConfirm = (item) => { + props.onChange?.(item) + } + return <> + + + + {productInfo.product_name} + + {sale_mode_name} + + goLink('/pages/codeSetting/codeColorList/index')}> + 编辑 + + + + + {productInfo?.product_color_details?.map(citem => )} + + setStatus(!upStatus)}>{upStatus ? '展开' : '收起'} + + setShowEdit(false)} onConfirm={onConfirm} /> + +}) diff --git a/src/pages/codeSetting/components/counter/index.tsx b/src/pages/codeSetting/components/counter/index.tsx index f53b518..ea738f3 100644 --- a/src/pages/codeSetting/components/counter/index.tsx +++ b/src/pages/codeSetting/components/counter/index.tsx @@ -86,33 +86,33 @@ const CounterDisplayName = (props: params) => { } const onInputEven = (e) => { - const res = e.detail.value - if (res === '') { - onChange?.(minNum) - } - else if (!Number.isNaN(Number(res))) { - let count = formatDigits(res) - count = checkData(count) - onChange?.(parseFloat(count as string)) - } - else { - const num = parseFloat(res) - if (!Number.isNaN(num)) { - let count = formatDigits(num) - count = checkData(count) - onChange?.(count as number) - } - else { - onChange?.(defaultNum) - } - } + // const res = e.detail.value + // if (res === '') { + // onChange?.(minNum) + // } + // else if (!Number.isNaN(Number(res))) { + // let count = formatDigits(res) + // count = checkData(count) + // onChange?.(parseFloat(count as string)) + // } + // else { + // const num = parseFloat(res) + // if (!Number.isNaN(num)) { + // let count = formatDigits(num) + // count = checkData(count) + // onChange?.(count as number) + // } + // else { + // onChange?.(defaultNum) + // } + // } } const onBluerEven = (e) => { const num = parseFloat(e.detail.value) if (e.detail.value == '') { - onBlue?.(minNum) - setValue({ count: minNum }) + onBlue?.(minNum < 0 ? 0 : minNum) + setValue({ count: minNum < 0 ? 0 : minNum }) } else if (!Number.isNaN(num)) { let count = formatDigits(num) diff --git a/src/pages/codeSetting/components/main/index.module.scss b/src/pages/codeSetting/components/main/index.module.scss new file mode 100644 index 0000000..a3260de --- /dev/null +++ b/src/pages/codeSetting/components/main/index.module.scss @@ -0,0 +1,41 @@ +.code_list__main { + background-color: #f7f7f7; + min-height: 100vh; + padding-bottom: 150px; + .code_list__head { + background-color: #fff; + padding: 24px; + box-sizing: border-box; + } + .code_list_con { + padding: 0 24px; + margin-top: 24px; + .code_des { + padding: 0 32px 32px 32px; + background-color: #fff; + border-radius: 16px; + margin-top: 24px; + .code_des_title { + height: 82px; + line-height: 82px; + font-size: 28px; + color: #000000; + border-bottom: 1px solid rgba(0, 0, 0, 0.1); + } + .code_des_item { + display: flex; + justify-content: space-between; + font-size: 28px; + color: rgba(0, 0, 0, 0.8); + margin-top: 24px; + .code_des_weight { + font-weight: 500; + } + .code_des_price { + color: #f64861; + font-weight: 500; + } + } + } + } +} diff --git a/src/pages/codeSetting/components/main/index.tsx b/src/pages/codeSetting/components/main/index.tsx new file mode 100644 index 0000000..425c989 --- /dev/null +++ b/src/pages/codeSetting/components/main/index.tsx @@ -0,0 +1,191 @@ +import { Text, View } from '@tarojs/components' +import { useRouter } from '@tarojs/taro' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import PayeeHead from '../payeeHead' +import type { CompanyItem } from '../payeeHead' +import WholeOrderSetting from '../wholeOrderSetting' +import type { BottomItem } from '../bottomBtn' +import BottomBtn from '../bottomBtn' +import ProductSetting from '../productSetting' +import ColorSetting from '../colorSetting' +import styles from './index.module.scss' +import SelectList from '@/components/selectList' +import { CreateCustomCodeApi, CustomPrintCalculationApi, GetCustomCodeDetailApi, GetCustomCodeInitApi, UpdateCustomCodeApi } from '@/api/codeManage' +import { formatPriceDiv, formatWeightDiv } from '@/common/fotmat' +import { useCurrenCode } from '@/context/ContextCodeSetting' +import { alert } from '@/common/common' + +export default () => { + const { productData, dispatch } = useCurrenCode() + const { custom_print_id, sale_order_id } = useRouter().params + const selectList = [ + { value: 1, label: '按整单' }, + { value: 2, label: '按面料' }, + { value: 3, label: '按颜色' }, + ] + const [modeIndex, setModeIndex] = useState(1) + const getTypeSelect = useCallback((index) => { + setModeIndex(index) + dispatch({ type: 'changeAdjustType', data: index }) + getDataInit() + }, []) + + const companyId = useRef(0) + const [codeData, setCodeData] = useState(null) + + // 获取新增码单详情 + const { fetchData: getCustomCodeInit } = GetCustomCodeInitApi() + const onCustomCodeInit = async() => { + const res = await getCustomCodeInit({ id: sale_order_id }) + setCodeData(() => res?.data) + } + + // 获取码单编辑详情 + const { fetchData: getCustomCodeDetail } = GetCustomCodeDetailApi() + const onGetCustomCodeDetail = async() => { + const res = await getCustomCodeDetail({ id: custom_print_id }) + setCodeData(() => res?.data) + } + + const getDataInit = async() => { + if (custom_print_id) { + await onGetCustomCodeDetail() + } + else { + await onCustomCodeInit() + } + dispatch({ type: 'changeSaveStatus', data: false }) + } + + useEffect(() => { + getDataInit() + }, []) + + useEffect(() => { + if (codeData) { + companyId.current = codeData?.default_title_id + codeData && dispatch({ + type: 'setInitData', + data: codeData, + sale_order_id: sale_order_id || 0, + custom_print_id: custom_print_id || 0, + }) + setCustomTotal(() => ({ + total_weight_error: codeData.total_weight_error, + total_sale_weight: codeData.total_sale_weight, + total_amount: codeData.total_amount, + })) + } + }, [codeData]) + + // 默认抬头 + const company = useMemo(() => { + console.log('productData默认抬头:::', productData) + return { + title: productData?.data?.title_name, + purchaser_name: productData?.data?.purchaser_name, + phone: productData?.data?.purchaser_phone, + is_default: true, + } + }, [productData]) + + // 修改码单 + const { fetchData: createCustomCodeApi } = CreateCustomCodeApi() + const { fetchData: updateCustomCodeApi } = UpdateCustomCodeApi() + + // 获取码单抬头 + const getCompany = useCallback((val: CompanyItem) => { + companyId.current = val?.id || 0 + }, []) + + // 按钮事件 + const onBottomClick = useCallback((type: BottomItem) => { + (async() => { + if (type === 'save') { + const res = custom_print_id + ? await updateCustomCodeApi({ ...productData.admin_data }) + : await createCustomCodeApi({ ...productData.admin_data }) + if (res.success) { + getDataInit() + dispatch({ type: 'changeSaveStatus', data: true }) + alert.success('保存成功!') + } + } + })() + }, [productData]) + + // 自定义码单合计数据 + const [customTotal, setCustomTotal] = useState({ + total_weight_error: 0, + total_sale_weight: 0, + total_amount: 0, + }) + useEffect(() => { + if (productData.admin_data) { + updateCustomOrderTotal(productData.admin_data) + } + }, [productData.admin_data]) + + // 更新合计数据 + const { fetchData: customPrintCalculationApi } = CustomPrintCalculationApi() + const updateCustomOrderTotal = async(updateData) => { + const res = await customPrintCalculationApi(updateData) + if (res.success) { + setCustomTotal(() => ({ + total_weight_error: res?.data?.total_weight_error, + total_sale_weight: res?.data?.total_sale_weight, + total_amount: res?.data?.total_amount, + })) + } + } + + return + + + + + + + {modeIndex == 1 && } + + + {modeIndex == 2 && } + + + {modeIndex == 3 && } + + + 自定义单据信息 + + 合计空差 + {formatWeightDiv(customTotal.total_weight_error)}kg + + + 合计重量 + {formatWeightDiv(customTotal.total_sale_weight)}kg + + + 合计金额 + ¥{formatPriceDiv(customTotal.total_amount)} + + + + 原始单据信息 + + 合计空差 + {formatWeightDiv(productData?.data?.original_total_weight_error)}kg + + + 合计重量 + {formatWeightDiv(productData?.data?.original_total_sale_weight)}kg + + + 合计金额 + ¥{formatPriceDiv(productData?.data?.original_total_amount)} + + + + + + +} diff --git a/src/pages/codeSetting/components/payeeHead/index.tsx b/src/pages/codeSetting/components/payeeHead/index.tsx index 86584ef..35ee971 100644 --- a/src/pages/codeSetting/components/payeeHead/index.tsx +++ b/src/pages/codeSetting/components/payeeHead/index.tsx @@ -1,18 +1,44 @@ import { Text, View } from '@tarojs/components' +import Taro from '@tarojs/taro' +import { useEffect, useState } from 'react' import styles from './index.module.scss' import IconFont from '@/components/iconfont/iconfont' +import { goLink } from '@/common/common' +import NameLabel from '@/components/nameLabel' -export default () => { - return - +export interface CompanyItem { title: string; purchaser_name: string; phone: string; is_default?: boolean; id?: number } +interface CompanyParam { + defaultValue?: CompanyItem + onSelect?: (data: CompanyItem) => void +} +export default (props: CompanyParam) => { + const { defaultValue, onSelect } = props + const [data, setData] = useState() + useEffect(() => { + if (defaultValue) { setData(() => defaultValue) } + }, [defaultValue]) + const goLink = () => { + Taro.navigateTo({ + url: '/pages/weightList/index', + events: { + getSelectCompanyEvent(data) { + console.log('data::', data) + setData(() => data) + onSelect?.(data as CompanyItem) + }, + }, + }) + } + return + - 布郡纺织有限公司 - 默认抬头 + {data?.title} + {data?.is_default && 默认抬头} - 杨翰俊 - 189467876642 + {data?.purchaser_name} + {data?.phone} diff --git a/src/pages/codeSetting/components/productItem/index.tsx b/src/pages/codeSetting/components/productItem/index.tsx index 204c329..d0f1c9a 100644 --- a/src/pages/codeSetting/components/productItem/index.tsx +++ b/src/pages/codeSetting/components/productItem/index.tsx @@ -1,24 +1,72 @@ import { Text, View } from '@tarojs/components' +import { memo, useCallback, useEffect, useMemo, useState } from 'react' import styles from './index.module.scss' import LabAndImg from '@/components/LabAndImg' import IconFont from '@/components/iconfont/iconfont' +import { formatPriceDiv, formatWeightDiv } from '@/common/fotmat' +import PopupModal from '@/components/popupModal' +import { useCurrenCode } from '@/context/ContextCodeSetting' -export default () => { +interface Param { + codeItem: any +} + +type IndexParam = { + onChange: (val: string) => void +} & Param + +export default (props: Param) => { + const { codeItem } = props + const { dispatch, productData } = useCurrenCode() + const index = codeItem.index_str.split('_') + const productInfo = productData.data.product_details[index[0]] + const codeInfo = productInfo.product_color_details[index[1]] + const getNewName = useCallback((name) => { + productData.data.product_details[index[0]].product_color_details[index[1]] = { ...codeInfo, product_color_name: name } + productData.data.product_details[index[0]] = { ...productData.data.product_details[index[0]] } + dispatch({ type: 'updateData', data: { ...productData.data } }) + }, [codeItem]) + return <> + + +} + +const Index = memo((props: IndexParam) => { + const { codeItem } = props + const [showEdit, setShowEdit] = useState(false) + const [title, setTitle] = useState('') + + const countData = useMemo(() => { + console.log('codeItem内容:::', codeItem) + return { + old: `重量:${formatWeightDiv(codeItem?.weight_setting)}kg|空差: ${formatWeightDiv(codeItem?.weight_error_setting)}k|单价:¥${formatPriceDiv(codeItem?.price_setting)}/kg`, + new: `重量:${formatWeightDiv(codeItem?.original_weight)}kg|空差: ${formatWeightDiv(codeItem?.original_weight_error)}k|单价:¥${formatWeightDiv(codeItem?.original_price)}/kg`, + } + }, [codeItem]) + const onUpdate = () => { + console.log('点击了') + setTitle(codeItem.product_color_name) + setShowEdit(true) + } + const onConfirm = (item) => { + props.onChange?.(item) + } return - + - - 001# 环保黑 + + {codeItem?.product_color_name} - x2条 + x{codeItem?.roll}条 - 重量:400.5kg|空差: 50.5k|单价:¥100.0/kg - 重量:400.5kg|空差: 50.5k|单价:¥100.0/kg + {countData.old} + {countData.new} + setShowEdit(false)} onConfirm={onConfirm} /> -} +}) diff --git a/src/pages/codeSetting/components/productSetting/index.module.scss b/src/pages/codeSetting/components/productSetting/index.module.scss index cd3bcc5..e3b5813 100644 --- a/src/pages/codeSetting/components/productSetting/index.module.scss +++ b/src/pages/codeSetting/components/productSetting/index.module.scss @@ -5,27 +5,4 @@ margin-top: 24px; padding: 0 32px 32px 32px; box-sizing: border-box; - .product_list__item { - .product_list__item--title { - height: 82px; - font-size: 28px; - display: flex; - color: #000000; - align-items: center; - .product_title { - margin-right: 8px; - } - .mode_status { - width: 60px; - height: 30px; - font-size: 20px; - background: #337fff; - border-radius: 8px; - text-align: center; - line-height: 30px; - color: #fff; - margin-left: 8px; - } - } - } } diff --git a/src/pages/codeSetting/components/productSetting/index.tsx b/src/pages/codeSetting/components/productSetting/index.tsx index d5d68fe..41f228d 100644 --- a/src/pages/codeSetting/components/productSetting/index.tsx +++ b/src/pages/codeSetting/components/productSetting/index.tsx @@ -1,23 +1,27 @@ import { Text, View } from '@tarojs/components' +import { memo, useCallback, useMemo, useState } from 'react' +import classNames from 'classnames' +import type { NumberParam } from '../settingNumber' import SettingNumber from '../settingNumber' import ProductItem from '../productItem' import styles from './index.module.scss' +import ProductBlock from './productBlock' import IconFont from '@/components/iconfont/iconfont' import LabAndImg from '@/components/LabAndImg' -export default () => { +interface Parma { + orderData: any +} +export default memo((props: Parma) => { + const { orderData = {} } = props + const productList = useMemo(() => { + return orderData?.product_details || [] + }, [orderData]) return <> - - - - 5215# 26S双纱亲水滑爽棉 - - 大货 - - - {new Array(5).fill('').map((item, index) => )} - + {productList?.map((item) => { + return + })} -} +}) diff --git a/src/pages/codeSetting/components/productSetting/productBlock/index.module.scss b/src/pages/codeSetting/components/productSetting/productBlock/index.module.scss new file mode 100644 index 0000000..423b0d7 --- /dev/null +++ b/src/pages/codeSetting/components/productSetting/productBlock/index.module.scss @@ -0,0 +1,42 @@ +.product_list__item { + .product_list__item--title { + height: 82px; + font-size: 28px; + display: flex; + color: #000000; + align-items: center; + .product_title { + margin-right: 8px; + } + .mode_status { + width: 60px; + height: 30px; + font-size: 20px; + background: #337fff; + border-radius: 8px; + text-align: center; + line-height: 30px; + color: #fff; + margin-left: 8px; + } + } + .product_list__item--con { + transition: height 0.3s ease-in-out; + overflow: hidden; + } + .open_up_icon { + transform: rotate(180deg); + } + .close_up_icon { + transform: rotate(0); + } + .up_btn { + width: 100%; + height: 72px; + display: flex; + justify-content: center; + align-items: center; + font-size: 28px; + color: rgba(0, 0, 0, 0.4); + } +} diff --git a/src/pages/codeSetting/components/productSetting/productBlock/index.tsx b/src/pages/codeSetting/components/productSetting/productBlock/index.tsx new file mode 100644 index 0000000..52f3c15 --- /dev/null +++ b/src/pages/codeSetting/components/productSetting/productBlock/index.tsx @@ -0,0 +1,105 @@ +import { Text, View } from '@tarojs/components' +import { memo, useCallback, useContext, useRef, useState } from 'react' +import classNames from 'classnames' +import Big from 'big.js' +import ProductItem from '../../productItem' +import type { NumberParam } from '../../settingNumber' +import SettingNumber from '../../settingNumber' +import styles from './index.module.scss' +import IconFont from '@/components/iconfont/iconfont' +import PopupModal from '@/components/popupModal' +import { useCurrenCode } from '@/context/ContextCodeSetting' + +interface Parma { + productInfo: any + sale_mode_name: string +} + +type IndexParam = { + onChangeName: (val: string) => void + onChangeNumber: NumberParam +} & Parma + +export default memo((props: Parma) => { + const { productInfo } = props + const { dispatch, productData } = useCurrenCode() + const index = productInfo.index_str.split('_')[0] + const getNewName = useCallback((name) => { + productData.data.product_details[index] = { + ...productData.data.product_details[index], + product_name: name, + } + dispatch({ type: 'updateData', data: { ...productData.data } }) + }, [productInfo]) + + // 更新整体数据 + const updateData = useRef({ + price: 0, + weight: 0, + weight_error: 0, + adjust_type: 1, + }) + const changeNumber: NumberParam = useCallback((num, type) => { + if (type === 'weight') { + updateData.current.weight = num * 1000 + } + else if (type === 'sale_price') { + updateData.current.price = num * 100 + } + else { + updateData.current.weight_error = num * 1000 + } + // 需要传给后端 + productData.data.product_details[index].weight_admin = updateData.current.weight + productData.data.product_details[index].price_admin = updateData.current.price + productData.data.product_details[index].weight_error_admin = updateData.current.weight_error + + // 更新原始数组 + productData.data.product_details[index]?.product_color_details?.map((item) => { + item.weight_setting = Big(updateData.current.weight).times(item.roll).add(item.weight).toNumber() + item.weight_error_setting = Big(updateData.current.weight_error).times(item.roll).add(item.weight_error).toNumber() + item.price_setting = Big(updateData.current.price).add(item.price).toNumber() + }) + productData.data.product_details[index] = JSON.parse(JSON.stringify(productData.data.product_details[index])) + dispatch({ type: 'updateData', data: { ...productData.data } }) + }, [productInfo]) + + return <> + + +}) + +const Index = memo((props: IndexParam) => { + const { productInfo, sale_mode_name } = props + const [showEdit, setShowEdit] = useState(false) + const [upStatus, setStatus] = useState(false) + const [title, setTitle] = useState('') + console.log('productInfo内容:::', productInfo) + const onUpdate = () => { + setTitle(productInfo.product_name) + setShowEdit(true) + } + const onConfirm = (item) => { + props.onChangeName?.(item) + } + + const getNumber: NumberParam = (num, type) => { + props.onChangeNumber?.(num, type) + } + + return <> + + + {productInfo.product_name} + + {sale_mode_name} + + + + {productInfo?.product_color_details?.map(citem => )} + + setStatus(!upStatus)}>{upStatus ? '展开' : '收起'} + + setShowEdit(false)} onConfirm={onConfirm} /> + +}) diff --git a/src/pages/codeSetting/components/settingNumber/index.tsx b/src/pages/codeSetting/components/settingNumber/index.tsx index 5190547..637fa8d 100644 --- a/src/pages/codeSetting/components/settingNumber/index.tsx +++ b/src/pages/codeSetting/components/settingNumber/index.tsx @@ -1,20 +1,58 @@ import { View } from '@tarojs/components' +import { useContext, useEffect, useState } from 'react' import Counter from '../counter' import styles from './index.module.scss' +import { debounce } from '@/common/util' +import { useCurrenCode } from '@/context/ContextCodeSetting' -export default () => { +export type Mode = 'weight'|'weight_error'|'sale_price' +export type NumberParam = (num: number, type: Mode) => void +interface Props { + onNumber?: NumberParam +} +export default (props: Props) => { + const { productData } = useCurrenCode() + const { onNumber } = props + const [defaultNum, setDefaultNum] = useState({ + weight: 0, + weight_error: 0, + sale_price: 0, + }) + useEffect(() => { + if (productData.save_status) { + console.log('重置数据:::', productData.save_status) + setDefaultNum(() => ({ + weight: 0, + weight_error: 0, + sale_price: 0, + })) + } + }, [productData.save_status]) + const getNumber: NumberParam = debounce((num, type) => { + onNumber?.(num, type) + if (type === 'weight') { + defaultNum.weight = num + } + else if (type === 'sale_price') { + defaultNum.sale_price = num + } + else { + defaultNum.weight_error = num + } + setDefaultNum(() => ({ ...defaultNum })) + }, 300) return 重量 - + getNumber(num, 'weight')} onBlue={num => getNumber(num, 'weight')} /> 空差 - + getNumber(num, 'weight_error')} onBlue={num => getNumber(num, 'weight_error')} /> 单价 - + getNumber(num, 'sale_price')} onBlue={num => getNumber(num, 'sale_price')} /> } diff --git a/src/pages/codeSetting/components/wholeOrderSetting/index.module.scss b/src/pages/codeSetting/components/wholeOrderSetting/index.module.scss index 01985ea..25b8145 100644 --- a/src/pages/codeSetting/components/wholeOrderSetting/index.module.scss +++ b/src/pages/codeSetting/components/wholeOrderSetting/index.module.scss @@ -5,37 +5,4 @@ margin-top: 24px; padding: 0 32px 0 32px; box-sizing: border-box; - .product_list__item { - .product_list__item--title { - height: 82px; - font-size: 28px; - display: flex; - color: #000000; - align-items: center; - border-bottom: 1px solid rgba(0, 0, 0, 0.1); - .product_title { - margin-right: 8px; - } - .mode_status { - width: 60px; - height: 30px; - font-size: 20px; - background: #337fff; - border-radius: 8px; - text-align: center; - line-height: 30px; - color: #fff; - margin-left: 8px; - } - } - .up_btn { - width: 100%; - height: 72px; - display: flex; - justify-content: center; - align-items: center; - font-size: 28px; - color: rgba(0, 0, 0, 0.4); - } - } } diff --git a/src/pages/codeSetting/components/wholeOrderSetting/index.tsx b/src/pages/codeSetting/components/wholeOrderSetting/index.tsx index 271c7d6..04a1a89 100644 --- a/src/pages/codeSetting/components/wholeOrderSetting/index.tsx +++ b/src/pages/codeSetting/components/wholeOrderSetting/index.tsx @@ -1,26 +1,65 @@ -import { Text, View } from '@tarojs/components' +import { View } from '@tarojs/components' +import { memo, useCallback, useMemo, useRef } from 'react' +import Big from 'big.js' +import type { NumberParam } from '../settingNumber' import SettingNumber from '../settingNumber' -import ProductItem from '../productItem' import styles from './index.module.scss' -import IconFont from '@/components/iconfont/iconfont' -import LabAndImg from '@/components/LabAndImg' +import ProductBlock from './productBlock' +import { useCurrenCode } from '@/context/ContextCodeSetting' + +interface Parma { + orderData: any + onUpdateData?: (val: any) => void +} +export default memo((props: Parma) => { + const { dispatch, productData } = useCurrenCode() + const { orderData = {}, onUpdateData } = props + const productList = useMemo(() => { + console.log('productData123:::', orderData) + if (!orderData?.product_details) { return [] } + return orderData?.product_details + }, [orderData]) + + // 更新整体数据 + const updateData = useRef({ + price: 0, + weight: 0, + weight_error: 0, + adjust_type: 1, + }) + const getNumber: NumberParam = useCallback((num, type) => { + if (type === 'weight') { + updateData.current.weight = num * 1000 + } + else if (type === 'sale_price') { + updateData.current.price = num * 100 + } + else { + updateData.current.weight_error = num * 1000 + } + // 需要传给后端 + productData.data.weight_admin = updateData.current.weight + productData.data.price_admin = updateData.current.price + productData.data.weight_error_admin = updateData.current.weight_error + + // 更新原始数组 + productList?.map((item) => { + item?.product_color_details?.map((citem) => { + citem.weight_setting = Big(updateData.current.weight).times(citem.roll).add(citem.weight).toNumber() + citem.weight_error_setting = Big(updateData.current.weight_error).times(citem.roll).add(citem.weight_error).toNumber() + citem.price_setting = Big(updateData.current.price).add(citem.price).toNumber() + }) + }) + orderData.product_details = productList + dispatch({ type: 'updateData', data: JSON.parse(JSON.stringify(orderData)) }) + }, [productList]) -export default () => { return <> - + - - - 5215# 26S双纱亲水滑爽棉 - - 大货 - - - {new Array(5).fill('').map((item, index) => )} - - 收起 - - + {productList?.map((item) => { + return + })} -} +}) diff --git a/src/pages/codeSetting/components/wholeOrderSetting/productBlock/index.module.scss b/src/pages/codeSetting/components/wholeOrderSetting/productBlock/index.module.scss new file mode 100644 index 0000000..f6fc705 --- /dev/null +++ b/src/pages/codeSetting/components/wholeOrderSetting/productBlock/index.module.scss @@ -0,0 +1,43 @@ +.product_list__item { + .product_list__item--title { + height: 82px; + font-size: 28px; + display: flex; + color: #000000; + align-items: center; + border-bottom: 1px solid rgba(0, 0, 0, 0.1); + .product_title { + margin-right: 8px; + } + .mode_status { + width: 60px; + height: 30px; + font-size: 20px; + background: #337fff; + border-radius: 8px; + text-align: center; + line-height: 30px; + color: #fff; + margin-left: 8px; + } + } + .product_list__item--con { + transition: height 0.3s ease-in-out; + overflow: hidden; + } + .open_up_icon { + transform: rotate(180deg); + } + .close_up_icon { + transform: rotate(0); + } + .up_btn { + width: 100%; + height: 72px; + display: flex; + justify-content: center; + align-items: center; + font-size: 28px; + color: rgba(0, 0, 0, 0.4); + } +} diff --git a/src/pages/codeSetting/components/wholeOrderSetting/productBlock/index.tsx b/src/pages/codeSetting/components/wholeOrderSetting/productBlock/index.tsx new file mode 100644 index 0000000..2b9bb51 --- /dev/null +++ b/src/pages/codeSetting/components/wholeOrderSetting/productBlock/index.tsx @@ -0,0 +1,62 @@ +import { Text, View } from '@tarojs/components' +import { memo, useCallback, useContext, useState } from 'react' +import classNames from 'classnames' +import ProductItem from '../../productItem' +import styles from './index.module.scss' +import IconFont from '@/components/iconfont/iconfont' +import PopupModal from '@/components/popupModal' +import { useCurrenCode } from '@/context/ContextCodeSetting' + +interface Parma { + productInfo: any + sale_mode_name: string +} + +type IndexParam = { + onChange: (val: string) => void +} & Parma + +export default memo((props: Parma) => { + const { productInfo } = props + const { dispatch, productData } = useCurrenCode() + const getNewName = useCallback((name) => { + const index = productInfo.index_str.split('_')[0] + productData.data.product_details[index] = { + ...productData.data.product_details[index], + product_name: name, + } + dispatch({ type: 'updateData', data: { ...productData.data } }) + }, [productInfo]) + return <> + + +}) + +const Index = memo((props: IndexParam) => { + const { productInfo, sale_mode_name } = props + const [showEdit, setShowEdit] = useState(false) + const [upStatus, setStatus] = useState(false) + const [title, setTitle] = useState('') + console.log('productInfo内容:::', productInfo) + const onUpdate = () => { + setTitle(productInfo.product_name) + setShowEdit(true) + } + const onConfirm = (item) => { + props.onChange?.(item) + } + return <> + + + {productInfo.product_name} + + {sale_mode_name} + + + {productInfo?.product_color_details?.map(citem => )} + + setStatus(!upStatus)}>{upStatus ? '展开' : '收起'} + + setShowEdit(false)} onConfirm={onConfirm} /> + +}) diff --git a/src/pages/codeSetting/index.module.scss b/src/pages/codeSetting/index.module.scss index a3260de..e69de29 100644 --- a/src/pages/codeSetting/index.module.scss +++ b/src/pages/codeSetting/index.module.scss @@ -1,41 +0,0 @@ -.code_list__main { - background-color: #f7f7f7; - min-height: 100vh; - padding-bottom: 150px; - .code_list__head { - background-color: #fff; - padding: 24px; - box-sizing: border-box; - } - .code_list_con { - padding: 0 24px; - margin-top: 24px; - .code_des { - padding: 0 32px 32px 32px; - background-color: #fff; - border-radius: 16px; - margin-top: 24px; - .code_des_title { - height: 82px; - line-height: 82px; - font-size: 28px; - color: #000000; - border-bottom: 1px solid rgba(0, 0, 0, 0.1); - } - .code_des_item { - display: flex; - justify-content: space-between; - font-size: 28px; - color: rgba(0, 0, 0, 0.8); - margin-top: 24px; - .code_des_weight { - font-weight: 500; - } - .code_des_price { - color: #f64861; - font-weight: 500; - } - } - } - } -} diff --git a/src/pages/codeSetting/index.tsx b/src/pages/codeSetting/index.tsx index 05195b9..fb58ade 100644 --- a/src/pages/codeSetting/index.tsx +++ b/src/pages/codeSetting/index.tsx @@ -1,70 +1,10 @@ -import { Text, View } from '@tarojs/components' -import classnames from 'classnames' -import { useCallback, useState } from 'react' -import styles from './index.module.scss' -import PayeeHead from './components/payeeHead' -import Counter from './components/counter' -import SettingNumber from './components/settingNumber' -import WholeOrderSetting from './components/wholeOrderSetting' -import BottomBtn from './components/bottomBtn' -import ProductSetting from './components/productSetting' -import ColorSetting from './components/colorSetting' -import SelectList from '@/components/selectList' -import useLogin from '@/use/useLogin' -import IconFont from '@/components/iconfont/iconfont' -import LabAndImg from '@/components/LabAndImg' +import Main from './components/main' +import ContextCodeSetting from '@/context/ContextCodeSetting' export default () => { - const selectList = [ - { value: 1, label: '按整单' }, - { value: 2, label: '按面料' }, - { value: 3, label: '按颜色' }, - ] - const [modeIndex, setModeIndex] = useState(1) - const getTypeSelect = useCallback((index) => { - setModeIndex(index) - }, []) - return - - - - - - {modeIndex == 1 && } - {modeIndex == 2 && } - {modeIndex == 3 && } - - 自定义单据信息 - - 合计空差 - 60kg - - - 合计重量 - 230.2kg - - - 合计金额 - ¥22,332.00 - - - - 原始单据信息 - - 合计空差 - 60kg - - - 合计重量 - 230.2kg - - - 合计金额 - ¥22,332.00 - - - - - - + return <> + +
+ + } diff --git a/src/pages/order/index.tsx b/src/pages/order/index.tsx index 3d29822..b556792 100644 --- a/src/pages/order/index.tsx +++ b/src/pages/order/index.tsx @@ -287,7 +287,7 @@ const Order = () => { [orderDetail], ) return ( - + {(orderDetail?.status != SaleorderstatusWaitingPrePayment.value && ) || ( diff --git a/src/pages/user/index.tsx b/src/pages/user/index.tsx index 855a9cd..c7b4f07 100644 --- a/src/pages/user/index.tsx +++ b/src/pages/user/index.tsx @@ -59,7 +59,7 @@ export default () => { const menuList = [ { label: '地址管理', icon: 'icon-dizhiguanli', callback: () => goLink('/pages/addressManager/index') }, - { label: '码单管理', icon: 'icon-mdgl', icon_status: 'local', callback: () => goLink('/pages/weightList/index') }, + { label: '码单管理', icon: 'icon-mdgl', icon_status: 'local', callback: () => goLink('/pages/codeList/index') }, { label: '颜色对比', icon: 'icon-yanseduibi', callback: () => goLink('/pages/sampleComparison/index') }, { label: '我的客服', icon: 'icon-wodekefu', text: '7x24小时服务', callback: () => (set_customer_service_show(true)) }, ] diff --git a/src/pages/weightList/components/companyItem/index.tsx b/src/pages/weightList/components/companyItem/index.tsx index 99d8c15..6bd6aa3 100644 --- a/src/pages/weightList/components/companyItem/index.tsx +++ b/src/pages/weightList/components/companyItem/index.tsx @@ -4,12 +4,14 @@ import IconFont from '@/components/iconfont/iconfont' import { goLink } from '@/common/common' import NameLabel from '@/components/nameLabel' +export interface CompanyItem { title: string; purchaser_name: string; id: number; phone: string } export interface CompanyParam { - value: { title: string; purchaser_name: string; id: number; phone: string } + value: CompanyItem + onClick?: (val: CompanyItem) => void } export default (props: CompanyParam) => { - const { value } = props - return goLink(`/pages/weightListAdd/index?type=edit&id=${value.id}`)}> + const { value, onClick } = props + return onClick?.(value)}> {value?.title } diff --git a/src/pages/weightList/index.tsx b/src/pages/weightList/index.tsx index 17ca569..c8bb7d9 100644 --- a/src/pages/weightList/index.tsx +++ b/src/pages/weightList/index.tsx @@ -1,10 +1,10 @@ import { Button, Navigator, ScrollView, Text, View } from '@tarojs/components' +import Taro, { getCurrentPages, showModal } from '@tarojs/taro' import { memo, useEffect, useState } from 'react' import CompanyItem from './components/companyItem' import { weightDeleteApi, weightListApi } from '@/api/weightList' import './index.scss' -import Taro, { showModal } from '@tarojs/taro' import { alert } from '@/common/common' const weightListManager = () => { @@ -16,7 +16,6 @@ const weightListManager = () => { } interface Params{ refresherEnabled?: boolean// 是否开启刷新 - onSelect?: (item: any, index: number) => void// 列表选择 } // 码单列表 @@ -60,17 +59,23 @@ const WeightList = (props: Params) => { }, })) } + const onSelect = (item) => { + const pages = getCurrentPages() + const current = pages[pages.length - 1] + const eventChannel = current.getOpenerEventChannel() + eventChannel.emit('getSelectCompanyEvent', item) + Taro.navigateBack() + } return ( { - // data.length>0? state?.data?.list?.length > 0 - ? state?.data?.list?.map((item, index) => { + ? state?.data?.list?.map((item) => { return ( - - + + ) }) diff --git a/src/styles/mixins/index.scss b/src/styles/mixins/index.scss new file mode 100644 index 0000000..e0a243b --- /dev/null +++ b/src/styles/mixins/index.scss @@ -0,0 +1,18 @@ +/** + * Mixins + */ + +/* library */ +// @import './libs/absolute-center'; +// @import './libs/clearfix'; +// @import './libs/line'; +// @import './libs/overlay'; +// @import './libs/shade'; +@import './libs/tint'; +@import './libs/flex'; +// @import './libs/border'; +// @import './libs/active'; +// @import './libs/disabled'; +// @import './libs/placeholder'; +// @import './libs/alignhack'; +// @import './libs/hairline'; diff --git a/src/styles/mixins/libs/flex.scss b/src/styles/mixins/libs/flex.scss new file mode 100644 index 0000000..576204a --- /dev/null +++ b/src/styles/mixins/libs/flex.scss @@ -0,0 +1,50 @@ +@mixin display-flex { + display: flex; +} + +@mixin flex-wrap($value: nowrap) { + flex-wrap: $value; +} + +@mixin align-items($value: stretch) { + align-items: $value; + @if $value == flex-start { + -webkit-box-align: start; + } @else if $value == flex-end { + -webkit-box-align: end; + } @else { + -webkit-box-align: $value; + } +} + +@mixin align-content($value: flex-start) { + align-content: $value; +} + +@mixin justify-content($value: flex-start) { + justify-content: $value; + @if $value == flex-start { + -webkit-box-pack: start; + } @else if $value == flex-end { + -webkit-box-pack: end; + } @else if $value == space-between { + -webkit-box-pack: justify; + } @else { + -webkit-box-pack: $value; + } +} + +/* Flex Item */ +@mixin flex($fg: 1, $fs: null, $fb: null) { + flex: $fg $fs $fb; + -webkit-box-flex: $fg; +} + +@mixin flex-order($n) { + order: $n; + -webkit-box-ordinal-group: $n; +} + +@mixin align-self($value: auto) { + align-self: $value; +} diff --git a/src/styles/mixins/libs/tint.scss b/src/styles/mixins/libs/tint.scss new file mode 100644 index 0000000..31d6970 --- /dev/null +++ b/src/styles/mixins/libs/tint.scss @@ -0,0 +1,23 @@ +/** + * Mixes a color with white. It's different from lighten() + * + * @param {color} $color + * @param {number (percentage)} $percent [The amout of white to be mixed in] + * @return {color} + * + * @example + * .element { + * background-color: tint(#6ecaa6 , 40%); + * } + * + * // CSS Output + * .element { + * background-color: #a8dfc9; + * } + */ +// @function tint( +// $color, +// $percent +// ) { +// @return mix(#FFF, $color, $percent); +// } diff --git a/src/styles/variables/default.scss b/src/styles/variables/default.scss new file mode 100644 index 0000000..8ef0cb5 --- /dev/null +++ b/src/styles/variables/default.scss @@ -0,0 +1,457 @@ +/** + * Default variables + */ + +@import '../mixins/libs/tint'; + +$hd: 2 !default; // 基本单位 + +/* The Color of O2Team Brand */ +$color-brand: #337fff !default; +$color-brand-light: #78A4F4 !default; +$color-brand-dark: #346FC2 !default; + +/* Color */ +$color-success: #13CE66 !default; +$color-error: #FF4949 !default; +$color-warning: #FFC82C !default; +$color-info: #78A4FA !default; + +/* Color Palette */ +$color-black-0: #000 !default; +$color-black-1: #333 !default; +$color-black-2: #7F7F7F !default; +$color-black-3: #B2B2B2 !default; + +$color-grey-0: #333 !default; +$color-grey-1: #666 !default; +$color-grey-2: #999 !default; +$color-grey-3: #CCC !default; +$color-grey-4: #E5E5E5 !default; +$color-grey-5: #F0F0F0 !default; +$color-grey-6: #F7F7F7 !default; + +$color-white: #FFF !default; + +/* Text Color */ +$color-text-base: #333 !default; // 文字的基本色 +$color-text-base-inverse: #FFF !default; // 反色 +$color-text-secondary: #36D57D !default; // 辅助色 +$color-text-placeholder: #C9C9C9 !default; +$color-text-disabled: #CCC !default; +$color-text-title: #2C405A !default; // 文章标题 +$color-text-paragraph: #3F536E !default; // 文章段落 + +/* Link */ +$color-link: #6190E8 !default; +$color-link-hover: #79A1EB !default; +$color-link-active: #4F7DE2 !default; +$color-link-disabled: #BFBFBF !default; + +/* 背景色 */ +$color-bg: #FFF !default; +$color-bg-base: #FAFBFC !default; +$color-bg-light: #ECF5FD !default; +$color-bg-lighter: tint($color-bg-light, 50%) !default; +$color-bg-grey: #F7F7F7 !default; + +/* 边框颜色 */ +$color-border-base: #C5D9E8 !default; +$color-border-split: tint($color-border-base, 20%) !default; // 分割线 +$color-border-light: tint($color-border-base, 30%) !default; +$color-border-lighter: tint($color-border-base, 50%) !default; +$color-border-lightest: tint($color-border-base, 80%) !default; +$color-border-grey: #CCC !default; + +/* 图标颜色 */ +$color-icon-base: #CCC !default; + +/* Border Radius */ +$border-radius-sm: 2px * $hd !default; +$border-radius-md: 4px * $hd !default; +$border-radius-lg: 6px * $hd !default; +$border-radius-circle: 50% !default; + +/* 透明度 */ +$opacity-active: 0.6 !default; // Button 等组件点击态额透明度 +$opacity-disabled: 0.3 !default; // Button 等组件禁用态的透明度 + +/* Font */ +$font-size-xs: 10px * $hd !default; // 非常用字号,用于标签 +$font-size-sm: 12px * $hd !default; // 用于辅助信息 +$font-size-base: 14px * $hd !default; // 常用字号 +$font-size-lg: 16px * $hd !default; // 常规标题 +$font-size-xl: 18px * $hd !default; // 大标题 +$font-size-xxl: 20px * $hd !default; // 用于大号的数字 + +/* Line Height */ +$line-height-base: 1 !default; // 单行 +$line-height-en: 1.3 !default; // 英文多行 +$line-height-zh: 1.5 !default; // 中文多行 + +/* 水平间距 */ +$spacing-h-sm: 5px * $hd !default; +$spacing-h-md: 8px * $hd !default; +$spacing-h-lg: 12px * $hd !default; +$spacing-h-xl: 16px * $hd !default; + +/* 垂直间距 */ +$spacing-v-xs: 3px * $hd !default; +$spacing-v-sm: 6px * $hd !default; +$spacing-v-md: 9px * $hd !default; +$spacing-v-lg: 12px * $hd !default; +$spacing-v-xl: 15px * $hd !default; + +/* 图标尺寸 */ +$icon-size-sm: 18px * $hd !default; +$icon-size-md: 22px * $hd !default; +$icon-size-lg: 36px * $hd !default; + +/* z-index */ +$zindex-divider: 100 !default; +$zindex-steps: 500 !default; +$zindex-tab: 600 !default; +$zindex-form: 700 !default; +$zindex-nav: 800 !default; +$zindex-search-bar: 800 !default; +$zindex-indexes: 805 !default; +$zindex-flot-layout: 810 !default; +$zindex-drawer: 900 !default; +$zindex-modal: 1000 !default; +$zindex-action-sheet: 1010 !default; +$zindex-picker: 1010 !default; +$zindex-curtain: 1080 !default; +$zindex-message: 1090 !default; +$zindex-toast: 1090 !default; + +/* timing function */ +$timing-func: cubic-bezier(0.36, 0.66, 0.04, 1) !default; + +/** +* CSS cubic-bezier timing functions +* http://bourbon.io/docs/#timing-functions +*/ +$ease-in-quad: cubic-bezier(0.550, 0.085, 0.680, 0.530) !default; +$ease-in-cubic: cubic-bezier(0.550, 0.055, 0.675, 0.190) !default; +$ease-in-quart: cubic-bezier(0.895, 0.030, 0.685, 0.220) !default; +$ease-in-quint: cubic-bezier(0.755, 0.050, 0.855, 0.060) !default; +$ease-in-sine: cubic-bezier(0.470, 0.000, 0.745, 0.715) !default; +$ease-in-expo: cubic-bezier(0.950, 0.050, 0.795, 0.035) !default; +$ease-in-circ: cubic-bezier(0.600, 0.040, 0.980, 0.335) !default; +$ease-in-back: cubic-bezier(0.600, -0.280, 0.735, 0.045) !default; + +$ease-out-quad: cubic-bezier(0.250, 0.460, 0.450, 0.940) !default; +$ease-out-cubic: cubic-bezier(0.215, 0.610, 0.355, 1.000) !default; +$ease-out-quart: cubic-bezier(0.165, 0.840, 0.440, 1.000) !default; +$ease-out-quint: cubic-bezier(0.230, 1.000, 0.320, 1.000) !default; +$ease-out-sine: cubic-bezier(0.390, 0.575, 0.565, 1.000) !default; +$ease-out-expo: cubic-bezier(0.190, 1.000, 0.220, 1.000) !default; +$ease-out-circ: cubic-bezier(0.075, 0.820, 0.165, 1.000) !default; +$ease-out-back: cubic-bezier(0.175, 0.885, 0.320, 1.275) !default; + +$ease-in-out-quad: cubic-bezier(0.455, 0.030, 0.515, 0.955) !default; +$ease-in-out-cubic: cubic-bezier(0.645, 0.045, 0.355, 1.000) !default; +$ease-in-out-quart: cubic-bezier(0.770, 0.000, 0.175, 1.000) !default; +$ease-in-out-quint: cubic-bezier(0.860, 0.000, 0.070, 1.000) !default; +$ease-in-out-sine: cubic-bezier(0.445, 0.050, 0.550, 0.950) !default; +$ease-in-out-expo: cubic-bezier(1.000, 0.000, 0.000, 1.000) !default; +$ease-in-out-circ: cubic-bezier(0.785, 0.135, 0.150, 0.860) !default; +$ease-in-out-back: cubic-bezier(0.680, -0.550, 0.265, 1.550) !default; + +/** + * 组件变量 + */ + +/* Accordion */ +$at-accordion-color-arrow: $color-grey-3 !default; + +/* Activity Indicator */ +$at-activity-indicator-font-size: 28px !default; +$at-activity-indicator-font-color: $color-grey-2 !default; + +/* Avatar */ +$at-avatar-color: $color-white !default; +$at-avatar-bg-color: $color-grey-4 !default; +$at-avatar-size-sm: 80px !default; +$at-avatar-size-md: 100px !default; +$at-avatar-size-lg: 120px !default; + +/* Badge */ +$at-badge-color: $color-white !default; +$at-badge-bg-color: $color-error !default; +$at-badge-bg: $at-badge-bg-color !default; +$at-badge-font-size: $font-size-xs !default; +$at-badge-dot-size: 20px !default; + +/* Button */ +$at-button-height: 92px !default; +$at-button-height-sm: 60px !default; +$at-button-color: $color-brand !default; +$at-button-border-color-primary: $color-brand !default; +$at-button-border-color-secondary: $color-brand !default; +$at-button-bg: $at-button-color !default; + +/* Float Button */ +$at-fab-size: 56px * $hd !default; +$at-fab-size-sm: 40px * $hd !default; +$at-fab-icon-size: 24px * $hd !default; +$at-fab-bg-color: $color-brand; +$at-fab-bg-color-active: $color-brand-dark; +$at-fab-box-shadow: + 0 6px 10px -2px rgba(0, 0, 0, 0.2), + 0 12px 20px 0 rgba(0, 0, 0, 0.14), + 0 2px 36px 0 rgba(0, 0, 0, 0.12) !default; +$at-fab-box-shadow-active: + 0 14px 16px -8px rgba(0, 0, 0, 0.2), + 0 24px 34px 4px rgba(0, 0, 0, 0.14), + 0 10px 44px 8px rgba(0, 0, 0, 0.12) !default; + +/* Calendar */ +$at-calendar-day-size: 72px !default; +$at-calendar-mark-size: 8px !default; +$at-calendar-header-color: #B8BFC6 !default; +$at-calendar-main-color: $color-brand !default; +$at-calendar-day-color: #7C86A2 !default; + +/* Card */ +$at-card-thumb-size: 32px !default; +$at-card-icon-size: 32px !default; +$at-card-title-color: $color-text-title !default; +$at-card-extra-color: $color-text-title !default; +$at-card-info-color: $color-text-base !default; +$at-card-note-color: $color-grey-2 !default; + +/* Checkbox */ +$at-checkbox-circle-size: 40px !default; +$at-checkbox-icon-size: $font-size-sm !default; +$at-checkbox-icon-color: $color-brand !default; +$at-checkbox-icon-color-checked: $color-white !default; +$at-checkbox-title-color: $color-text-base !default; +$at-checkbox-title-font-size: $font-size-lg !default; +$at-checkbox-desc-font-size: $font-size-sm !default; +$at-checkbox-desc-color: $color-grey-2 !default; + +/* Countdown */ +$at-countdown-font-size: $font-size-lg !default; +$at-countdown-num-color: $color-text-base !default; +$at-countdown-card-num-color: #FF4949 !default; +$at-countdown-card-num-bg-color: $color-white !default; + +/* Curtain */ +$at-curtain-btn-color: $color-white !default; + +/* Divider */ +$at-divider-height: 112px; +$at-divider-content-color: $color-brand !default; +$at-divider-font-size: $font-size-lg !default; +$at-divider-line-color: $color-grey-3 !default; + +/* Drawer */ +$at-drawer-content-width: 460px !default; + +/* FloatLayout */ +$float-layout-height-min: 600px !default; +$float-layout-height-max: 950px !default; +$float-layout-header-bg-color: $color-bg-grey !default; +$float-layout-title-color: $color-text-base !default; +$float-layout-title-font-size: $font-size-lg !default; +$float-layout-btn-color: $color-grey-3 !default; + +/* Grid */ +$at-grid-text-color: $color-text-base !default; +$at-grid-font-size: $font-size-lg !default; +$at-grid-img-size: 80px !default; +$at-gird-img-size-sm: 50px !default; + +/* ImagePicker */ +$at-image-picker-btn-add-color: $color-grey-3 !default; +$at-image-picker-btn-remove-color: $color-white !default; +$at-image-picker-btn-remove-bg-color: $color-grey-2 !default; + +/* Indexes */ +$at-indexes-nav-color: $color-link !default; +$at-indexes-nav-font-size: $font-size-sm !default; +$at-indexes-title-color: $color-black-2 !default; +$at-indexes-title-font-size: $font-size-sm !default; +$at-indexes-title-bg-color: $color-grey-6 !default; + +/* InputNumber */ +$at-input-number-text-color: $color-text-base !default; +$at-input-number-font-size: $font-size-base !default; +$at-input-number-font-size-lg: $font-size-xl !default; +$at-input-number-btn-color: $color-brand !default; +$at-input-number-btn-size: 30px !default; +$at-input-number-btn-size-lg: 36px !default; +$at-input-number-width-min: 80px !default; +$at-input-number-width-min-lg: 120px !default; + +/* Input */ +$at-input-label-color: $color-text-base !default; +$at-input-text-color: $color-text-base !default; +$at-input-font-size: $font-size-lg !default; +$at-input-placeholder-color: $color-grey-3 !default; + +/* List */ +$at-list-thumb-size: 56px !default; +$at-list-arrow-color: $color-grey-3 !default; +$at-list-text-color: $color-text-base !default; +$at-list-content-color: $color-grey-2 !default; +$at-list-extra-color: $color-grey-2 !default; +$at-list-extra-width: 235px !default; + +/* LoadMore */ +$at-load-more-height: 80PX !default; +$at-load-more-tips-color: $color-grey-1 !default; +$at-load-more-tips-size: $font-size-lg !default; + +/* Loading */ +$at-loading-size: 36px !default; +$at-loading-color: $color-brand !default; + +/* Message */ +$at-message-color: $color-white !default; +$at-message-font-size: $font-size-base !default; +$at-message-bg-color: $color-info !default; + +/* Modal */ +$at-modal-width: 540px !default; +$at-modal-header-text-color: $color-text-base !default; +$at-modal-content-text-color: $color-text-base !default; +$at-modal-btn-default-color: $color-text-base !default; +$at-modal-btn-confirm-color: $color-brand !default; +$at-modal-bg-color: $color-white !default; + +/* NavBar */ +$at-nav-bar-title-color: $color-text-base !default; +$at-nav-bar-link-color: $color-brand !default; + +/* NoticeBar */ +$at-noticebar-text-color: #DE8C17 !default; +$at-noticebar-bg-color: #FCF6ED !default; +$at-noticebar-font-size: $font-size-sm !default; +$at-noticebar-icon-size: 30px !default; +$at-noticebar-btn-close-size: 32px !default; +$at-noticebar-btn-close-color: $color-grey-3 !default; + +/* Pagination */ +$at-pagination-margin: 40px !default; +$at-pagination-num-color: $color-text-base !default; +$at-pagination-num-font-size: $font-size-base !default; +$at-pagination-current-num-color: $color-brand !default; +$at-pagination-icon-color: $color-text-base !default; +$at-pagination-icon-font-size: 32px !default; + +/* Progress */ +$at-progress-height: 16px !default; +$at-progress-text-size: $font-size-sm !default; +$at-progress-icon-size: $font-size-xl !default; +$at-progress-inner-bg-color: $color-grey-6 !default; +$at-progress-bar-bg-color: $color-brand-light !default; +$at-progress-bar-bg-color-active: $color-white !default; + +/* Radio */ +$at-radio-title-color: $color-text-base !default; +$at-radio-title-size: $font-size-lg !default; +$at-radio-desc-color: $color-grey-2 !default; +$at-radio-desc-size: $font-size-sm !default; +$at-radio-check-color: $color-brand !default; + +/* Range */ +$at-range-slider-size: 28PX !default; +$at-range-rail-height: 2PX !default; +$at-range-rail-bg-color: #E9E9E9 !default; +$at-range-track-bg-color: $color-brand !default; +$at-range-slider-color: $color-white !default; +$at-range-slider-shadow: 0 0 4PX 0 rgba(0, 0, 0, 0.2) !default; + +/* Rate */ +$at-rate-icon-size: 20PX !default; +$at-rate-star-color: #ECECEC !default; +$at-rate-star-color-on: #FFCA3E !default; + +/* SearchBar */ +$at-search-bar-btn-color: $color-white !default; +$at-search-bar-btn-bg-color: $color-brand !default; + +/* SegmentedControl */ +$at-segmented-control-color: $color-brand !default; +$at-segmented-control-color-active: $color-white !default; +$at-segmented-control-bg-color: transparent !default; +$at-segmented-control-font-size: $font-size-base !default; + +/* Slider */ +$at-slider-text-color: $color-grey-2 !default; +$at-slider-text-size: $font-size-base !default; + +/* Steps */ +$at-steps-circle-size: 56px !default; +$at-steps-icon-size: $font-size-sm !default; +$at-steps-color: $color-white !default; +$at-steps-color-active: $color-grey-2 !default; +$at-steps-bg-color: $color-grey-4 !default; +$at-steps-bg-color-active: $color-brand !default; +$at-steps-line-color: $color-grey-3 !default; +$at-steps-title-color: $color-black-0 !default; +$at-steps-title-size: $font-size-lg !default; +$at-steps-desc-color: $color-grey-3 !default; +$at-steps-desc-size: $font-size-sm !default; + +/* SwipeAction */ +$at-swipe-action-color: $color-white !default; +$at-swipe-action-font-size: $font-size-base !default; +$at-swipe-action-bg-color: $color-white !default; +$at-swipe-action-option-bg-color: $color-grey-2 !default; + +/* Switch */ +$at-switch-title-color: $color-text-base !default; +$at-switch-title-size: $font-size-base !default; + +/* TabBar */ +$at-tab-bar-bg-color: $color-white !default; +$at-tab-bar-color: $color-text-base !default; +$at-tab-bar-color-active: $color-brand !default; +$at-tab-bar-font-size: $font-size-base !default; +$at-tab-bar-icon-color: $color-grey-0 !default; +$at-tab-bar-icon-font-size: 48px !default; +$at-tab-bar-icon-image-size: 50px !default; + +/* Tabs */ +$at-tabs-color: $color-text-base !default; +$at-tabs-color-active: $color-brand !default; +$at-tabs-font-size: $font-size-base !default; +$at-tabs-line-height: 1PX !default; +$at-tabs-underline-color: $color-grey-5 !default; +$at-tabs-bg-color: $color-bg !default; + +/* Tag */ +$at-tag-height: 60px !default; +$at-tag-height-sm: 40px !default; +$at-tag-color: $color-grey-1 !default; +$at-tag-color-primary: $color-grey-1 !default; +$at-tag-color-active: $color-brand-light !default; +$at-tag-color-primary-active: $color-text-base-inverse !default; +$at-tag-font-size: $font-size-base !default; +$at-tag-font-size-sm: $font-size-xs !default; +$at-tag-bg-color: $color-bg-grey !default; +$at-tag-bg-color-primary: $color-bg-grey !default; +$at-tag-bg-color-active: $color-white !default; +$at-tag-bg-color-primary-active: $at-tag-color-active !default; +$at-tag-border-color: $at-tag-bg-color !default; +$at-tag-border-color-primary: $at-tag-bg-color !default; +$at-tag-border-color-active: $at-tag-color-active !default; + +/* Textarea */ +$at-textarea-font-size: $font-size-lg !default; +$at-textarea-tips-color: $color-text-placeholder !default; +$at-textarea-tips-size: $font-size-base !default; + +/* Timeline */ +$at-timeline-offset-left: 40px !default; +$at-timeline-title-color: $color-grey-0 !default; +$at-timeline-title-font-size: $font-size-base !default; +$at-timeline-desc-color: $color-grey-1 !default; +$at-timeline-desc-font-size: $font-size-sm !default; +$at-timeline-dot-size: 24px !default; +$at-timeline-dot-color: $color-bg !default; +$at-timeline-dot-border-color: $color-brand-light !default; +$at-timeline-line-color: $color-border-lighter !default;